diff --git a/apps/backend/package.json b/apps/backend/package.json index c9c9ed48..02f6c0de 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -30,13 +30,13 @@ "format": "prettier --write ." }, "dependencies": { - "@nao/shared": "*", "@ai-sdk/anthropic": "^3.0.15", "@ai-sdk/google": "^3.0.16", "@ai-sdk/mistral": "^3.0.13", "@ai-sdk/openai": "^3.0.1", "@fastify/formbody": "^8.0.2", "@fastify/static": "^8.1.0", + "@nao/shared": "*", "@slack/web-api": "^7.13.0", "@trpc/server": "^11.8.1", "@types/nodemailer": "^7.0.9", @@ -51,13 +51,14 @@ "fastify-plugin": "^5.1.0", "fastify-raw-body": "^5.0.0", "fastify-type-provider-zod": "^6.1.0", + "mcporter": "^0.7.3", "minimatch": "^10.1.1", "nodemailer": "^7.0.13", "pg": "^8.16.3", "postgres": "^3.4.8", + "posthog-node": "^5.21.2", "react": "^19.2.4", "react-dom": "^19.2.4", - "posthog-node": "^5.21.2", "superjson": "^2.2.6", "zod": "^4.2.1" }, diff --git a/apps/backend/src/agents/tools/index.ts b/apps/backend/src/agents/tools/index.ts index 5672840d..db59fc68 100644 --- a/apps/backend/src/agents/tools/index.ts +++ b/apps/backend/src/agents/tools/index.ts @@ -1,3 +1,4 @@ +import { mcpService } from '../../services/mcp.service'; import displayChart from './display-chart'; import executeSql from './execute-sql'; import grep from './grep'; @@ -15,3 +16,9 @@ export const tools = { search, suggest_follow_ups: suggestFollowUps, }; + +export const getTools = () => { + const mcpTools = mcpService.getMcpTools(); + + return { ...tools, ...mcpTools }; +}; diff --git a/apps/backend/src/components/email/emailButton.tsx b/apps/backend/src/components/email/email-button.tsx similarity index 100% rename from apps/backend/src/components/email/emailButton.tsx rename to apps/backend/src/components/email/email-button.tsx diff --git a/apps/backend/src/components/email/emailLayout.tsx b/apps/backend/src/components/email/email-layout.tsx similarity index 100% rename from apps/backend/src/components/email/emailLayout.tsx rename to apps/backend/src/components/email/email-layout.tsx diff --git a/apps/backend/src/components/email/resetPasswordEmail.tsx b/apps/backend/src/components/email/reset-password-email.tsx similarity index 86% rename from apps/backend/src/components/email/resetPasswordEmail.tsx rename to apps/backend/src/components/email/reset-password-email.tsx index 5abe1878..6d06d3e9 100644 --- a/apps/backend/src/components/email/resetPasswordEmail.tsx +++ b/apps/backend/src/components/email/reset-password-email.tsx @@ -1,7 +1,7 @@ import { EmailData } from '../../types/email'; -import { EmailButton } from './emailButton'; -import { EmailLayout } from './emailLayout'; -import { WarningBox } from './warningBox'; +import { EmailButton } from './email-button'; +import { EmailLayout } from './email-layout'; +import { WarningBox } from './warning-box'; export function ResetPasswordEmail({ userName, temporaryPassword, loginUrl, projectName }: EmailData) { return ( diff --git a/apps/backend/src/components/email/userAddedToProjectEmail.tsx b/apps/backend/src/components/email/user-added-to-project-email.tsx similarity index 91% rename from apps/backend/src/components/email/userAddedToProjectEmail.tsx rename to apps/backend/src/components/email/user-added-to-project-email.tsx index 4f6e44c6..8a4bc0cc 100644 --- a/apps/backend/src/components/email/userAddedToProjectEmail.tsx +++ b/apps/backend/src/components/email/user-added-to-project-email.tsx @@ -1,7 +1,7 @@ import { EmailData } from '../../types/email'; -import { EmailButton } from './emailButton'; -import { EmailLayout } from './emailLayout'; -import { WarningBox } from './warningBox'; +import { EmailButton } from './email-button'; +import { EmailLayout } from './email-layout'; +import { WarningBox } from './warning-box'; export function UserAddedToProjectEmail({ userName, projectName, loginUrl, to, temporaryPassword }: EmailData) { const isNewUser = !!temporaryPassword; diff --git a/apps/backend/src/components/email/warningBox.tsx b/apps/backend/src/components/email/warning-box.tsx similarity index 100% rename from apps/backend/src/components/email/warningBox.tsx rename to apps/backend/src/components/email/warning-box.tsx diff --git a/apps/backend/src/env.ts b/apps/backend/src/env.ts index 7f95db3c..f203f1e1 100644 --- a/apps/backend/src/env.ts +++ b/apps/backend/src/env.ts @@ -35,6 +35,8 @@ const envSchema = z.object({ NAO_DEFAULT_PROJECT_PATH: z.string().optional(), + MCP_JSON_FILE_PATH: z.string().optional(), + POSTHOG_KEY: z.string().optional(), POSTHOG_HOST: z.url({ message: 'POSTHOG_HOST must be a valid URL' }).optional(), POSTHOG_DISABLED: z diff --git a/apps/backend/src/routes/chat.ts b/apps/backend/src/routes/chat.ts index 264a1bfd..1bef909c 100644 --- a/apps/backend/src/routes/chat.ts +++ b/apps/backend/src/routes/chat.ts @@ -2,9 +2,11 @@ import { createUIMessageStreamResponse } from 'ai'; import { z } from 'zod/v4'; import type { App } from '../app'; +import { env } from '../env'; import { authMiddleware } from '../middleware/auth'; import * as chatQueries from '../queries/chat.queries'; import { agentService } from '../services/agent.service'; +import { mcpService } from '../services/mcp.service'; import { posthog, PostHogEvent } from '../services/posthog.service'; import { UIMessage } from '../types/chat'; import { llmProviderSchema } from '../types/llm'; @@ -67,6 +69,10 @@ export const chatRoutes = async (app: App) => { return reply.status(403).send({ error: `You are not authorized to access this chat.` }); } + if (env.MCP_JSON_FILE_PATH) { + await mcpService.initializeMcpState(); + } + const agent = await agentService.create({ ...chat, userId, projectId }, abortController, modelSelection); posthog.capture(userId, PostHogEvent.MessageSent, { diff --git a/apps/backend/src/services/agent.service.ts b/apps/backend/src/services/agent.service.ts index d5ca91ad..bd7f0894 100644 --- a/apps/backend/src/services/agent.service.ts +++ b/apps/backend/src/services/agent.service.ts @@ -11,7 +11,7 @@ import { import { getInstructions } from '../agents/prompt'; import { CACHE_1H, CACHE_5M, createProviderModel } from '../agents/providers'; -import { tools } from '../agents/tools'; +import { getTools } from '../agents/tools'; import * as chatQueries from '../queries/chat.queries'; import * as llmConfigQueries from '../queries/project-llm-config.queries'; import { TokenCost, TokenUsage, UIChat, UIMessage } from '../types/chat'; @@ -131,7 +131,7 @@ export class AgentService { } class AgentManager { - private readonly _agent: ToolLoopAgent; + private readonly _agent: ToolLoopAgent, never>; constructor( readonly chat: AgentChat, @@ -142,7 +142,7 @@ class AgentManager { ) { this._agent = new ToolLoopAgent({ ...modelConfig, - tools, + tools: getTools(), // On step 1+: cache user message (stable) + current step's last message (loop leaf) prepareStep: ({ messages }) => { return { messages: this._addCache(messages) }; @@ -158,8 +158,7 @@ class AgentManager { }, ): ReadableStream { let error: unknown = undefined; - let result: StreamTextResult; - + let result: StreamTextResult, never>; return createUIMessageStream({ generateId: () => crypto.randomUUID(), execute: async ({ writer }) => { diff --git a/apps/backend/src/services/email.service.ts b/apps/backend/src/services/email.service.ts index c78a0ab0..6ea8da79 100644 --- a/apps/backend/src/services/email.service.ts +++ b/apps/backend/src/services/email.service.ts @@ -2,8 +2,8 @@ import type { Transporter } from 'nodemailer'; import nodemailer from 'nodemailer'; import { renderToString } from 'react-dom/server'; -import { ResetPasswordEmail } from '../components/email/resetPasswordEmail'; -import { UserAddedToProjectEmail } from '../components/email/userAddedToProjectEmail'; +import { ResetPasswordEmail } from '../components/email/reset-password-email'; +import { UserAddedToProjectEmail } from '../components/email/user-added-to-project-email'; import type { CreatedEmailData, EmailData, SendEmailParams } from '../types/email'; class EmailService { diff --git a/apps/backend/src/services/mcp.service.ts b/apps/backend/src/services/mcp.service.ts new file mode 100644 index 00000000..ea86d731 --- /dev/null +++ b/apps/backend/src/services/mcp.service.ts @@ -0,0 +1,231 @@ +import type { Tool } from '@ai-sdk/provider-utils'; +import { debounce } from '@nao/shared/utils'; +import { jsonSchema, type JSONSchema7 } from 'ai'; +import { readFileSync, watch } from 'fs'; +import { callOnce, createRuntime, type Runtime, ServerDefinition, ServerToolInfo } from 'mcporter'; + +import { env } from '../env'; +import { mcpJsonSchema, McpServerConfig, McpServerState } from '../types/mcp'; +import { prefixToolName, removePrefixToolName, sanitizeTools } from '../utils/tools'; +import { replaceEnvVars } from '../utils/utils'; + +export class McpService { + private _mcpJsonFilePath: string; + private _mcpServers: Record; + private _fileWatcher: ReturnType | null = null; + private _debouncedReconnect: () => void; + private _initialized = false; + private _mcpTools: Record = {}; + private _runtime: Runtime | null = null; + private _failedConnections: Record = {}; + private _toolsToServer: Map = new Map(); + public cachedMcpState: Record = {}; + + constructor() { + this._mcpJsonFilePath = env.MCP_JSON_FILE_PATH || ''; + this._mcpServers = {}; + + this._debouncedReconnect = debounce(async () => { + await this.loadMcpState(); + }, 2000); + this._setupFileWatcher(); + } + + public async initializeMcpState(): Promise { + if (this._initialized) { + return; + } + + await this.loadMcpState(); + this._initialized = true; + } + + public async loadMcpState(): Promise { + try { + await this._loadMcpServerFromFile(); + + await this._connectAllServers(); + + await this._cacheMcpState(); + } catch (error) { + console.error('[mcp] Failed to cache MCP state:', error); + throw error; + } + } + + public getMcpTools(): Record { + const sanitizedMcpTools = Object.fromEntries( + Object.entries(this._mcpTools).map(([name, tool]) => { + const inputSchema = tool.inputSchema; + + // If it's an AI SDK schema wrapper with jsonSchema getter + if (inputSchema && typeof inputSchema === 'object' && 'jsonSchema' in inputSchema) { + const originalJsonSchema = inputSchema.jsonSchema; + return [ + name, + { + ...tool, + inputSchema: { + ...inputSchema, + jsonSchema: sanitizeTools(originalJsonSchema), + }, + } as Tool, + ]; + } + + // Otherwise, sanitize the schema directly + return [ + name, + { + ...tool, + inputSchema: sanitizeTools(inputSchema), + } as Tool, + ]; + }), + ); + return sanitizedMcpTools; + } + + private async _loadMcpServerFromFile(): Promise { + if (!this._mcpJsonFilePath) { + this._mcpServers = {}; + return; + } + + try { + const fileContent = readFileSync(this._mcpJsonFilePath, 'utf8'); + const resolvedContent = replaceEnvVars(fileContent); + const content = mcpJsonSchema.parse(JSON.parse(resolvedContent)); + this._mcpServers = content.mcpServers; + } catch { + console.error( + `[mcp] Failed to read or parse MCP config file at ${this._mcpJsonFilePath}. Using empty configuration.`, + ); + this._mcpServers = {}; + } + } + + private async _connectAllServers(): Promise { + this._mcpTools = {}; + this._runtime = await createRuntime(); + + const connectionPromises = Object.entries(this._mcpServers).map(async ([serverName, serverConfig]) => { + try { + if (!this._runtime) { + throw new Error('Runtime not initialized'); + } + const definition = this._convertToServerDefinition(serverName, serverConfig); + this._runtime.registerDefinition(definition, { overwrite: true }); + await this._listTools(serverName); + return { serverName, success: true }; + } catch (error) { + console.error(`[mcp] Failed to connect to ${serverName}:`, error); + this._failedConnections[serverName] = (error as Error).message; + } + }); + + await Promise.all(connectionPromises); + } + + // Convert MCP server config to MCPorter server definition + private _convertToServerDefinition(name: string, config: McpServerConfig): ServerDefinition { + if (config.type === 'http') { + return { + name, + command: { + kind: 'http', + url: config.url!, + }, + }; + } + + return { + name, + command: { + kind: 'stdio', + command: config.command || '', + args: config.args || [], + cwd: process.cwd(), + }, + env: config.env, + }; + } + + private async _listTools(serverName: string): Promise { + if (!this._runtime) { + throw new Error('Runtime not initialized'); + } + + const tools = await this._runtime.listTools(serverName, { + includeSchema: true, + }); + + await this.cacheMcpTools(tools, serverName); + } + + private async cacheMcpTools(tools: ServerToolInfo[], serverName: string): Promise { + for (const tool of tools) { + const toolName = tool.name.startsWith(serverName) ? tool.name : prefixToolName(serverName, tool.name); + this._mcpTools[toolName] = { + description: tool.description, + inputSchema: jsonSchema(tool.inputSchema as JSONSchema7), + execute: async (toolArgs: Record) => { + return await this._callTool(toolName, toolArgs); + }, + }; + this._toolsToServer.set(toolName, serverName); + } + } + + private async _callTool(toolName: string, toolArgs: Record): Promise { + const serverName = this._toolsToServer.get(toolName); + if (!serverName) { + throw new Error(`Tool ${toolName} not found in any server`); + } + + const result = await callOnce({ + server: serverName, + toolName: removePrefixToolName(toolName), + args: toolArgs, + }); + + return result; + } + + private async _cacheMcpState(): Promise { + this.cachedMcpState = {}; + + for (const serverName of Object.keys(this._mcpServers)) { + const serverTools = Object.entries(this._mcpTools) + .filter(([toolName]) => this._toolsToServer.get(toolName) === serverName) + .map(([toolName, tool]) => ({ + name: toolName, + description: tool.description, + input_schema: tool.inputSchema, + })); + + this.cachedMcpState[serverName] = { + tools: serverTools, + error: this._failedConnections[serverName], + }; + } + } + + private _setupFileWatcher(): void { + if (!this._mcpJsonFilePath) { + return; + } + + try { + this._fileWatcher = watch(this._mcpJsonFilePath, (eventType) => { + if (eventType === 'change') { + this._debouncedReconnect(); + } + }); + } catch (error) { + console.error('[mcp] Failed to setup file watcher:', error); + } + } +} + +export const mcpService = new McpService(); diff --git a/apps/backend/src/trpc/mcp.routes.ts b/apps/backend/src/trpc/mcp.routes.ts new file mode 100644 index 00000000..ca66f719 --- /dev/null +++ b/apps/backend/src/trpc/mcp.routes.ts @@ -0,0 +1,13 @@ +import { mcpService } from '../services/mcp.service'; +import { adminProtectedProcedure, protectedProcedure, router } from './trpc'; + +export const mcpRoutes = router({ + getState: protectedProcedure.query(() => { + return mcpService.cachedMcpState; + }), + + reconnect: adminProtectedProcedure.mutation(async () => { + await mcpService.loadMcpState(); + return mcpService.cachedMcpState; + }), +}); diff --git a/apps/backend/src/trpc/router.ts b/apps/backend/src/trpc/router.ts index 58b8fe99..63268675 100644 --- a/apps/backend/src/trpc/router.ts +++ b/apps/backend/src/trpc/router.ts @@ -2,6 +2,7 @@ import { accountRoutes } from './account.routes'; import { chatRoutes } from './chat.routes'; import { feedbackRoutes } from './feedback.routes'; import { googleRoutes } from './google.routes'; +import { mcpRoutes } from './mcp.routes'; import { posthogRoutes } from './posthog.routes'; import { projectRoutes } from './project.routes'; import { router } from './trpc'; @@ -17,6 +18,7 @@ export const trpcRouter = router({ user: userRoutes, google: googleRoutes, account: accountRoutes, + mcp: mcpRoutes, }); export type TrpcRouter = typeof trpcRouter; diff --git a/apps/backend/src/types/mcp.ts b/apps/backend/src/types/mcp.ts new file mode 100644 index 00000000..a4b45d12 --- /dev/null +++ b/apps/backend/src/types/mcp.ts @@ -0,0 +1,37 @@ +import { z } from 'zod'; + +export interface McpServerConfig { + type?: 'http'; + url?: URL; + + // For stdio transport + command?: string; + args?: string[]; + env?: Record; +} + +export interface McpServerState { + tools: Array<{ + name: string; + description?: string; + input_schema: unknown; + }>; + error?: string; +} + +export const mcpJsonSchema = z.object({ + mcpServers: z.record( + z.string(), + z.object({ + type: z.enum(['http']).optional(), + url: z + .string() + .url() + .optional() + .transform((val) => (val ? new URL(val) : undefined)), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.record(z.string(), z.string()).optional(), + }), + ), +}); diff --git a/apps/backend/src/utils/tools.ts b/apps/backend/src/utils/tools.ts index ffd8d02f..e8ee0c88 100644 --- a/apps/backend/src/utils/tools.ts +++ b/apps/backend/src/utils/tools.ts @@ -4,6 +4,8 @@ import path from 'path'; import { env } from '../env'; +const MCP_TOOL_SEPARATOR = '__'; + /** * Directory names that should be excluded from tool operations (list, search, read). */ @@ -228,3 +230,69 @@ export const toVirtualPath = (realPath: string, projectFolder: string): string = const relativePath = path.relative(projectFolder, resolved); return '/' + relativePath; }; + +/** + * Sanitizes MCP tool schemas by: + * - Ensures all array types have an items property + * - Removes null from required arrays + * - Recursively processes nested objects + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function sanitizeTools(schema: any): any { + if (!schema || typeof schema !== 'object') { + return schema; + } + + const sanitized = { ...schema }; + + // Convert required: null to undefined + if (sanitized.required === null) { + delete sanitized.required; + } + + // Ensure array types have items + if (sanitized.type === 'array' && !sanitized.items) { + sanitized.items = {}; + } + + // Recursively process properties + if (sanitized.properties && typeof sanitized.properties === 'object') { + sanitized.properties = Object.fromEntries( + Object.entries(sanitized.properties).map(([key, value]) => { + return [key, sanitizeTools(value)]; + }), + ); + } + + // Recursively process items + if (sanitized.items) { + sanitized.items = sanitizeTools(sanitized.items); + } + + // Recursively process additionalProperties + if (sanitized.additionalProperties && typeof sanitized.additionalProperties === 'object') { + sanitized.additionalProperties = sanitizeTools(sanitized.additionalProperties); + } + + return sanitized; +} + +/** + * Creates prefixed tool name: "servername__toolname" + */ +export function prefixToolName(serverName: string, toolName: string): string { + return `${serverName}${MCP_TOOL_SEPARATOR}${toolName}`; +} + +/** + * Extracts server name and original tool name from prefixed name + * Returns: { serverName: "metabase", originalName: "list-dashboards" } + */ +export function removePrefixToolName(prefixedToolName: string): string { + const parts = prefixedToolName.split(MCP_TOOL_SEPARATOR); + if (parts.length >= 2) { + const toolName = parts.slice(1).join(MCP_TOOL_SEPARATOR); + return toolName; + } + return prefixedToolName; +} diff --git a/apps/backend/src/utils/utils.ts b/apps/backend/src/utils/utils.ts index 0f0e2331..c1f95bf9 100644 --- a/apps/backend/src/utils/utils.ts +++ b/apps/backend/src/utils/utils.ts @@ -41,3 +41,10 @@ export const isEmailDomainAllowed = (userEmail: string) => { }; export const regexPassword = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; + +export const replaceEnvVars = (fileContent: string) => { + const replaced = fileContent.replace(/\$\{(\w+)\}/g, (match, varName) => { + return process.env[varName] || match; + }); + return replaced; +}; diff --git a/apps/frontend/src/components/settings-add-user-form.tsx b/apps/frontend/src/components/settings-add-user-form.tsx index efaac654..9c3879a5 100644 --- a/apps/frontend/src/components/settings-add-user-form.tsx +++ b/apps/frontend/src/components/settings-add-user-form.tsx @@ -14,7 +14,7 @@ export function AddUserDialog() { const addUserToProject = useMutation( trpc.user.addUserToProject.mutationOptions({ - onSuccess: (data, _, __, ctx) => { + onSuccess: (data, variables, _, ctx) => { ctx.client.setQueryData(trpc.project.getAllUsersWithRoles.queryKey(), (oldData: any) => { if (!data.newUser) { return oldData; @@ -24,7 +24,7 @@ export function AddUserDialog() { handleClose(); if (data.password) { - setNewUser({ email: form.state.values.email, password: data.password }); + setNewUser({ email: variables.email, password: data.password }); setIsNewUserDialogOpen(true); } }, diff --git a/apps/frontend/src/components/settings-display-mcp.tsx b/apps/frontend/src/components/settings-display-mcp.tsx new file mode 100644 index 00000000..b6360174 --- /dev/null +++ b/apps/frontend/src/components/settings-display-mcp.tsx @@ -0,0 +1,148 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; +import { ChevronDown, ChevronUp } from 'lucide-react'; +import { useState } from 'react'; +import { trpc } from '@/main'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Spinner } from '@/components/ui/spinner'; +import { cn } from '@/lib/utils'; + +interface McpListProps { + isAdmin: boolean; +} + +export function McpList({ isAdmin }: McpListProps) { + const mcpState = useQuery({ + ...trpc.mcp.getState.queryOptions(), + refetchOnMount: 'always', + }); + const [expandedServers, setExpandedServers] = useState([]); + + const reconnectMutation = useMutation( + trpc.mcp.reconnect.mutationOptions({ + onSuccess: (data, _, __, ctx) => { + ctx.client.setQueryData(trpc.mcp.getState.queryKey(), () => { + return data; + }); + }, + }), + ); + + const handleReconnect = async () => { + await reconnectMutation.mutateAsync(); + }; + + const handleExpand = (serverName: string) => { + setExpandedServers((prev) => { + if (prev.includes(serverName)) { + return prev.filter((name) => name !== serverName); + } else { + return [...prev, serverName]; + } + }); + }; + + const mcpEntries = mcpState.data ? Object.entries(mcpState.data) : []; + + return ( +
+
+ {isAdmin && ( + + )} +
+ {mcpState.isLoading ? ( +
Loading MCP servers...
+ ) : ( +
+ + + + Name + Status + + + + + {mcpEntries.map(([name, state]) => { + const isConnected = !state.error; + const isExpanded = expandedServers.includes(name); + + return ( + <> + + {name} + +
+
+ {isConnected ? 'Running' : 'Error'} +
+
+
+ + + +
+ {isExpanded && ( + + +
+ {state.error ? ( +
+ {state.error} +
+ ) : ( + <> +
+ Tools ({state.tools.length}) +
+
+ {state.tools.map((tool) => ( + + {tool.name} + + ))} +
+ + )} +
+
+
+ )} + + ); + })} +
+
+
+ )} +
+ ); +} diff --git a/apps/frontend/src/main.tsx b/apps/frontend/src/main.tsx index ca44d8bf..9268014d 100644 --- a/apps/frontend/src/main.tsx +++ b/apps/frontend/src/main.tsx @@ -11,7 +11,6 @@ import { ThemeProvider } from './contexts/theme.provider'; import { SidebarProvider } from './contexts/sidebar.provider'; import { routeTree } from './routeTree.gen'; import reportWebVitals from './reportWebVitals'; -import { UserPageProvider } from './contexts/user.provider'; import type { TrpcRouter } from '@nao/backend/trpc'; // Register the router instance for type safety @@ -71,9 +70,7 @@ if (!rootElement.innerHTML) { - - - + diff --git a/apps/frontend/src/routes/_sidebar-layout.settings.profile.tsx b/apps/frontend/src/routes/_sidebar-layout.settings.profile.tsx index e4c4da81..b98ecd8c 100644 --- a/apps/frontend/src/routes/_sidebar-layout.settings.profile.tsx +++ b/apps/frontend/src/routes/_sidebar-layout.settings.profile.tsx @@ -1,4 +1,3 @@ -// import { useState } from 'react'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { signOut, useSession } from '@/lib/auth-client'; diff --git a/apps/frontend/src/routes/_sidebar-layout.settings.project.tsx b/apps/frontend/src/routes/_sidebar-layout.settings.project.tsx index 626e2b0d..2f0f4d1e 100644 --- a/apps/frontend/src/routes/_sidebar-layout.settings.project.tsx +++ b/apps/frontend/src/routes/_sidebar-layout.settings.project.tsx @@ -10,6 +10,7 @@ import { UsersList } from '@/components/settings-display-users'; import { ModifyUserForm } from '@/components/settings-modify-user-form'; import { GoogleConfigSection } from '@/components/settings-google-credentials-section'; import { SavedPrompts } from '@/components/settings-saved-prompts'; +import { McpList } from '@/components/settings-display-mcp'; export const Route = createFileRoute('/_sidebar-layout/settings/project')({ component: RouteComponent, @@ -77,6 +78,10 @@ function ProjectPage() { + + + + ) : ( diff --git a/apps/frontend/src/routes/_sidebar-layout.settings.tsx b/apps/frontend/src/routes/_sidebar-layout.settings.tsx index a415e756..34dc3d1a 100644 --- a/apps/frontend/src/routes/_sidebar-layout.settings.tsx +++ b/apps/frontend/src/routes/_sidebar-layout.settings.tsx @@ -1,4 +1,5 @@ import { createFileRoute, Outlet } from '@tanstack/react-router'; +import { UserPageProvider } from '@/contexts/user.provider'; export const Route = createFileRoute('/_sidebar-layout/settings')({ component: SettingsLayout, @@ -6,10 +7,12 @@ export const Route = createFileRoute('/_sidebar-layout/settings')({ function SettingsLayout() { return ( -
-
- + +
+
+ +
-
+ ); } diff --git a/apps/shared/package.json b/apps/shared/package.json index 53588e0b..fbc4bdb0 100644 --- a/apps/shared/package.json +++ b/apps/shared/package.json @@ -4,6 +4,7 @@ "type": "module", "exports": { "./posthog": "./src/posthog.ts", + "./utils": "./src/utils.ts", "./tools": "./src/tools/index.ts" }, "scripts": { diff --git a/apps/shared/src/utils.ts b/apps/shared/src/utils.ts new file mode 100644 index 00000000..a368d635 --- /dev/null +++ b/apps/shared/src/utils.ts @@ -0,0 +1,10 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function debounce any>(func: T, delay: number): (...args: Parameters) => void { + let timer: ReturnType; + return (...args: Parameters) => { + clearTimeout(timer); + timer = setTimeout(() => { + func(...args); + }, delay); + }; +} diff --git a/cli/nao_core/commands/chat.py b/cli/nao_core/commands/chat.py index 3f9d67c5..554e70d6 100644 --- a/cli/nao_core/commands/chat.py +++ b/cli/nao_core/commands/chat.py @@ -157,6 +157,10 @@ def shutdown_servers(): env["SLACK_SIGNING_SECRET"] = config.slack.signing_secret console.print("[bold green]✓[/bold green] Set Slack environment variables from config") + if config and config.mcp: + env["MCP_JSON_FILE_PATH"] = config.mcp.json_file_path + console.print("[bold green]✓[/bold green] Set MCP_JSON_FILE_PATH from config") + env["NAO_DEFAULT_PROJECT_PATH"] = str(Path.cwd()) env["BETTER_AUTH_URL"] = f"http://localhost:{SERVER_PORT}" env["FASTAPI_URL"] = f"http://localhost:{FASTAPI_PORT}" diff --git a/cli/nao_core/config/base.py b/cli/nao_core/config/base.py index 62dfebc9..e17c454a 100644 --- a/cli/nao_core/config/base.py +++ b/cli/nao_core/config/base.py @@ -13,6 +13,7 @@ from .databases import DATABASE_CONFIG_CLASSES, AnyDatabaseConfig, DatabaseType, parse_database_config from .llm import LLMConfig +from .mcp import McpConfig from .notion import NotionConfig from .repos import RepoConfig from .slack import SlackConfig @@ -27,6 +28,7 @@ class NaoConfig(BaseModel): notion: NotionConfig | None = Field(default=None, description="The Notion configurations") llm: LLMConfig | None = Field(default=None, description="The LLM configuration") slack: SlackConfig | None = Field(default=None, description="The Slack configuration") + mcp: McpConfig | None = Field(default=None, description="The MCP configuration") @model_validator(mode="before") @classmethod @@ -52,6 +54,7 @@ def promptConfig(cls, project_name: str, existing: "NaoConfig | None" = None) -> llm=cls._prompt_llm(), slack=cls._prompt_slack(), notion=cls._prompt_notion(), + mcp=cls._prompt_mcp(project_name), ) @classmethod @@ -62,6 +65,7 @@ def _prompt_extend(cls, existing: "NaoConfig") -> "NaoConfig": llm = existing.llm slack = existing.slack notion = existing.notion + mcp = existing.mcp # Show current config summary UI.title("Current Configuration") @@ -75,6 +79,8 @@ def _prompt_extend(cls, existing: "NaoConfig") -> "NaoConfig": UI.print(" Slack: configured") if notion: UI.print(" Notion: configured") + if mcp: + UI.print(" MCP: configured") UI.print() # Prompt for additions @@ -90,6 +96,9 @@ def _prompt_extend(cls, existing: "NaoConfig") -> "NaoConfig": if not notion: notion = cls._prompt_notion() + if not mcp: + mcp = cls._prompt_mcp(existing.project_name) + return cls( project_name=existing.project_name, databases=databases, @@ -97,6 +106,7 @@ def _prompt_extend(cls, existing: "NaoConfig") -> "NaoConfig": llm=llm, slack=slack, notion=notion, + mcp=mcp, ) @staticmethod @@ -164,6 +174,13 @@ def _prompt_notion() -> NotionConfig | None: return NotionConfig.promptConfig() return None + @staticmethod + def _prompt_mcp(project_name: str) -> McpConfig | None: + """Prompt for MCP configuration using questionary.""" + if ask_confirm("Set up MCP servers?", default=False): + return McpConfig.promptConfig(project_name) + return None + def save(self, path: Path) -> None: """Save the configuration to a YAML file.""" config_file = path / "nao_config.yaml" diff --git a/cli/nao_core/config/mcp/__init__.py b/cli/nao_core/config/mcp/__init__.py new file mode 100644 index 00000000..3463601d --- /dev/null +++ b/cli/nao_core/config/mcp/__init__.py @@ -0,0 +1,68 @@ +import json +from pathlib import Path + +from pydantic import BaseModel, Field + +from nao_core.ui import UI, ask_confirm, ask_text + +from .template import generate_default_template, generate_metabase_template + + +class McpConfig(BaseModel): + """MCP (Model Context Protocol) configuration.""" + + json_file_path: str = Field(description="Path to the MCP JSON configuration file") + + @classmethod + def promptConfig(cls, project_name: str) -> "McpConfig": + """Interactively prompt the user for MCP configuration.""" + UI.info("Enter the path to your MCP JSON configuration file:") + + json_file_path = ask_text( + "MCP JSON file path:", + required_field=True, + default="agent/mcps/mcp.json", + ) + if not json_file_path: + raise ValueError("MCP JSON file path is required") + + # Make path relative to project_name, if provided, and path is not absolute + path = Path(json_file_path).expanduser() + if not path.is_absolute(): + # Use project_name as base path if provided + base_path = Path(project_name) if project_name else Path.cwd() + path = base_path / path + path = path.resolve() + + if not path.exists(): + # Create parent directory if needed + path.parent.mkdir(parents=True, exist_ok=True) + + if ask_confirm( + "Create file with Metabase MCP config example?", + default=True, + ): + # Generate and write template with Metabase example + template = generate_metabase_template() + path.write_text(json.dumps(template, indent=2) + "\n") + + UI.success(f"Created MCP config file: {path}") + UI.info("Remember to set these environment variables:") + UI.info(" - METABASE_URL") + UI.info(" - METABASE_API_KEY") + else: + # Create default MCP configuration + template = generate_default_template() + path.write_text(json.dumps(template, indent=2) + "\n") + + UI.success(f"Created empty MCP config file: {path}") + UI.info("You can add MCP servers to this file later.") + + elif not path.is_file(): + raise ValueError(f"MCP JSON path exists but is not a file: {path}") + elif path.suffix.lower() != ".json": + raise ValueError(f"MCP file must be a JSON file (got {path.suffix}): {path}") + + return McpConfig( + json_file_path=str(path), + ) diff --git a/cli/nao_core/config/mcp/template.py b/cli/nao_core/config/mcp/template.py new file mode 100644 index 00000000..ba222dce --- /dev/null +++ b/cli/nao_core/config/mcp/template.py @@ -0,0 +1,31 @@ +"""MCP configuration template generator.""" + + +def generate_metabase_template() -> dict: + """Generate default MCP configuration with Metabase server example. + + Returns: + dict: MCP configuration with a Metabase server example that uses + environment variables for credentials. + """ + return { + "mcpServers": { + "metabase": { + "command": "npx", + "args": ["-y", "@getnao/metabase-mcp-server@latest"], + "env": { + "METABASE_URL": "${METABASE_URL}", + "METABASE_API_KEY": "${METABASE_API_KEY}", + }, + } + } + } + + +def generate_default_template() -> dict: + """Generate default empty MCP configuration. + + Returns: + dict: Empty MCP configuration with no servers defined. + """ + return {"mcpServers": {}} diff --git a/example/agent/mcps/mcp.json b/example/agent/mcps/mcp.json new file mode 100644 index 00000000..2ac677b4 --- /dev/null +++ b/example/agent/mcps/mcp.json @@ -0,0 +1,15 @@ +{ + "mcpServers": { + "metabase": { + "command": "npx", + "args": [ + "-y", + "@getnao/metabase-mcp-server@latest" + ], + "env": { + "METABASE_URL": "${METABASE_URL}", + "METABASE_API_KEY": "${METABASE_API_KEY}" + } + } + } +} diff --git a/package-lock.json b/package-lock.json index eb7c4d92..e74e501a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "fastify-plugin": "^5.1.0", "fastify-raw-body": "^5.0.0", "fastify-type-provider-zod": "^6.1.0", + "mcporter": "^0.7.3", "minimatch": "^10.1.1", "nodemailer": "^7.0.13", "pg": "^8.16.3", @@ -2418,6 +2419,18 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2470,6 +2483,12 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "license": "ISC" + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -2554,6 +2573,68 @@ "node": ">=8" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/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==", + "license": "MIT" + }, "node_modules/@nao/backend": { "resolved": "apps/backend", "link": true @@ -2848,6 +2929,15 @@ "node": ">=14" } }, + "node_modules/@oxc-project/types": { + "version": "0.103.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.103.0.tgz", + "integrity": "sha512-bkiYX5kaXWwUessFRSoXFkGIQTmc6dLGdxuRTrC+h8PSnIdZyuXHHlLAeTmOue5Br/a0/a7dHH0Gca6eXn9MKg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pinojs/redact": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", @@ -4575,6 +4665,230 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.57.tgz", + "integrity": "sha512-GoOVDy8bjw9z1K30Oo803nSzXJS/vWhFijFsW3kzvZCO8IZwFnNa6pGctmbbJstKl3Fv6UBwyjJQN6msejW0IQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.57.tgz", + "integrity": "sha512-9c4FOhRGpl+PX7zBK5p17c5efpF9aSpTPgyigv57hXf5NjQUaJOOiejPLAtFiKNBIfm5Uu6yFkvLKzOafNvlTw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.57.tgz", + "integrity": "sha512-6RsB8Qy4LnGqNGJJC/8uWeLWGOvbRL/KG5aJ8XXpSEupg/KQtlBEiFaYU/Ma5Usj1s+bt3ItkqZYAI50kSplBA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.57.tgz", + "integrity": "sha512-uA9kG7+MYkHTbqwv67Tx+5GV5YcKd33HCJIi0311iYBd25yuwyIqvJfBdt1VVB8tdOlyTb9cPAgfCki8nhwTQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.57.tgz", + "integrity": "sha512-3KkS0cHsllT2T+Te+VZMKHNw6FPQihYsQh+8J4jkzwgvAQpbsbXmrqhkw3YU/QGRrD8qgcOvBr6z5y6Jid+rmw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.57.tgz", + "integrity": "sha512-A3/wu1RgsHhqP3rVH2+sM81bpk+Qd2XaHTl8LtX5/1LNR7QVBFBCpAoiXwjTdGnI5cMdBVi7Z1pi52euW760Fw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.57.tgz", + "integrity": "sha512-d0kIVezTQtazpyWjiJIn5to8JlwfKITDqwsFv0Xc6s31N16CD2PC/Pl2OtKgS7n8WLOJbfqgIp5ixYzTAxCqMg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.57.tgz", + "integrity": "sha512-E199LPijo98yrLjPCmETx8EF43sZf9t3guSrLee/ej1rCCc3zDVTR4xFfN9BRAapGVl7/8hYqbbiQPTkv73kUg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.57.tgz", + "integrity": "sha512-++EQDpk/UJ33kY/BNsh7A7/P1sr/jbMuQ8cE554ZIy+tCUWCivo9zfyjDUoiMdnxqX6HLJEqqGnbGQOvzm2OMQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.57.tgz", + "integrity": "sha512-voDEBcNqxbUv/GeXKFtxXVWA+H45P/8Dec4Ii/SbyJyGvCqV1j+nNHfnFUIiRQ2Q40DwPe/djvgYBs9PpETiMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.57.tgz", + "integrity": "sha512-bRhcF7NLlCnpkzLVlVhrDEd0KH22VbTPkPTbMjlYvqhSmarxNIq5vtlQS8qmV7LkPKHrNLWyJW/V/sOyFba26Q==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.57.tgz", + "integrity": "sha512-rnDVGRks2FQ2hgJ2g15pHtfxqkGFGjJQUDWzYznEkE8Ra2+Vag9OffxdbJMZqBWXHVM0iS4dv8qSiEn7bO+n1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.57.tgz", + "integrity": "sha512-OqIUyNid1M4xTj6VRXp/Lht/qIP8fo25QyAZlCP+p6D2ATCEhyW4ZIFLnC9zAGN/HMbXoCzvwfa8Jjg/8J4YEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.2", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", @@ -7299,6 +7613,44 @@ "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", "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", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/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" + } + }, + "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" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -7857,6 +8209,30 @@ "readable-stream": "^3.4.0" } }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -8034,7 +8410,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -8238,7 +8613,34 @@ "url": "https://polar.sh/cva" } }, - "node_modules/clsx": { + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", @@ -8368,6 +8770,15 @@ "node": ">= 0.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" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -8393,6 +8804,15 @@ "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", "license": "MIT" }, + "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" + } + }, "node_modules/copy-anything": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", @@ -8419,6 +8839,23 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -9161,12 +9598,27 @@ "node": ">= 0.4" } }, + "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/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "license": "ISC" }, + "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" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -9350,6 +9802,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -9842,12 +10304,33 @@ "node": ">=0.10.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" + } + }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/eventsource-parser": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", @@ -9876,6 +10359,114 @@ "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", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/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" + } + }, + "node_modules/express/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" + } + }, + "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" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10173,6 +10764,27 @@ "node": ">=8" } }, + "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", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-my-way": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.4.0.tgz", @@ -10305,6 +10917,24 @@ "node": ">= 6" } }, + "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" + } + }, + "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/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -10384,6 +11014,18 @@ "node": ">=6.9.0" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -10858,6 +11500,15 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hono": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", + "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -11076,6 +11727,15 @@ "node": ">=12" } }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", @@ -11346,6 +12006,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -11417,6 +12089,12 @@ "dev": true, "license": "MIT" }, + "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-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -11528,6 +12206,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -11793,6 +12483,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -11812,6 +12508,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -12217,6 +12919,22 @@ "dev": true, "license": "MIT" }, + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", @@ -12321,6 +13039,38 @@ "node": ">= 0.4" } }, + "node_modules/mcporter": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/mcporter/-/mcporter-0.7.3.tgz", + "integrity": "sha512-egoPVYqTnWb3NjRIxo+xc8OrAI0dlPrJm9pAiZx0pImuNIV5rKhGtTnIfH/Y1ldGPVu74ibj3KR5c9U/QSdQFA==", + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "@modelcontextprotocol/sdk": "^1.25.1", + "acorn": "^8.15.0", + "commander": "^14.0.2", + "es-toolkit": "^1.43.0", + "jsonc-parser": "^3.3.1", + "ora": "^9.0.0", + "rolldown": "1.0.0-beta.57", + "zod": "^4.2.1" + }, + "bin": { + "mcporter": "dist/cli.js" + }, + "engines": { + "node": ">=20.11.0" + } + }, + "node_modules/mcporter/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -12610,6 +13360,15 @@ "dev": true, "license": "CC0-1.0" }, + "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" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -12619,6 +13378,18 @@ "node": ">= 0.10.0" } }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -13215,6 +13986,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -13357,6 +14140,15 @@ "dev": true, "license": "MIT" }, + "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" + } + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -13616,7 +14408,6 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -13665,6 +14456,18 @@ "node": ">=14.0.0" } }, + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -13674,6 +14477,21 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openapi-types": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", @@ -13699,6 +14517,40 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", + "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -13876,6 +14728,15 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "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" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -13927,6 +14788,16 @@ "node": "20 || >=22" } }, + "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", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -14177,6 +15048,15 @@ "node": ">= 6" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", @@ -14520,6 +15400,28 @@ "node": ">=12.0.0" } }, + "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", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/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" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -14546,6 +15448,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/query-selector-shadow-dom": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz", @@ -14653,6 +15570,15 @@ } } }, + "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" + } + }, "node_modules/raw-body": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", @@ -15164,6 +16090,22 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ret": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", @@ -15198,6 +16140,43 @@ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, + "node_modules/rolldown": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.57.tgz", + "integrity": "sha512-lMMxcNN71GMsSko8RyeTaFoATHkCh4IWU7pYF73ziMYjhHZWfVesC6GQ+iaJCvZmVjvgSks9Ks1aaqEkBd8udg==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.103.0", + "@rolldown/pluginutils": "1.0.0-beta.57" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.57", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.57", + "@rolldown/binding-darwin-x64": "1.0.0-beta.57", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.57", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.57", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.57", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.57", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.57", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.57", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.57", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.57", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.57", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.57" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.57", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.57.tgz", + "integrity": "sha512-aQNelgx14tGA+n2tNSa9x6/jeoCL9fkDeCei7nOKnHx0fEFRRMu5ReiITo+zZD5TzWDGGRjbSYCs93IfRIyTuQ==", + "license": "MIT" + }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", @@ -15248,6 +16227,22 @@ "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", "license": "MIT" }, + "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", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -15402,6 +16397,57 @@ "semver": "bin/semver" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/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" + } + }, + "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" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/seroval": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.0.tgz", @@ -15423,6 +16469,25 @@ "seroval": "^1.0" } }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -15522,7 +16587,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -15542,7 +16606,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -15559,7 +16622,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -15578,7 +16640,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -15828,6 +16889,18 @@ "devOptional": true, "license": "MIT" }, + "node_modules/stdin-discarder": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz", + "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -15876,6 +16949,22 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.1.tgz", + "integrity": "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string.prototype.padend": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", @@ -15968,6 +17057,33 @@ "url": "https://github.com/sponsors/wooorm" } }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -17536,6 +18652,45 @@ "node": ">= 0.8.0" } }, + "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", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/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" + } + }, + "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" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -17947,6 +19102,15 @@ "spdx-expression-parse": "^3.0.0" } }, + "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/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -18988,6 +20152,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", @@ -18997,6 +20173,15 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, "node_modules/zod-validation-error": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",