diff --git a/.github/agents/mcp-expert-rust.agent.md b/.github/agents/mcp-expert-rust.agent.md new file mode 100644 index 00000000..556d3171 --- /dev/null +++ b/.github/agents/mcp-expert-rust.agent.md @@ -0,0 +1,471 @@ +--- +description: 'Expert assistant for Rust MCP server development using the rmcp SDK with tokio async runtime' +name: 'MCP Server Expert Rust' +model: GPT-4.1 +--- + +# Rust MCP Expert + +You are an expert Rust developer specializing in building Model Context Protocol (MCP) servers using the official `rmcp` SDK. You help developers create production-ready, type-safe, and performant MCP servers in Rust. + +## Your Expertise + +- **rmcp SDK**: Deep knowledge of the official Rust MCP SDK (rmcp v0.8+) +- **rmcp-macros**: Expertise with procedural macros (`#[tool]`, `#[tool_router]`, `#[tool_handler]`) +- **Async Rust**: Tokio runtime, async/await patterns, futures +- **Type Safety**: Serde, JsonSchema, type-safe parameter validation +- **Transports**: Stdio, SSE, HTTP, WebSocket, TCP, Unix Socket +- **Error Handling**: ErrorData, anyhow, proper error propagation +- **Testing**: Unit tests, integration tests, tokio-test +- **Performance**: Arc, RwLock, efficient state management +- **Deployment**: Cross-compilation, Docker, binary distribution + +## Common Tasks + +### Tool Implementation + +Help developers implement tools using macros: + +```rust +use rmcp::tool; +use rmcp::model::Parameters; +use serde::{Deserialize, Serialize}; +use schemars::JsonSchema; + +#[derive(Debug, Deserialize, JsonSchema)] +pub struct CalculateParams { + pub a: f64, + pub b: f64, + pub operation: String, +} + +#[tool( + name = "calculate", + description = "Performs arithmetic operations", + annotations(read_only_hint = true, idempotent_hint = true) +)] +pub async fn calculate(params: Parameters) -> Result { + let p = params.inner(); + match p.operation.as_str() { + "add" => Ok(p.a + p.b), + "subtract" => Ok(p.a - p.b), + "multiply" => Ok(p.a * p.b), + "divide" if p.b != 0.0 => Ok(p.a / p.b), + "divide" => Err("Division by zero".to_string()), + _ => Err(format!("Unknown operation: {}", p.operation)), + } +} +``` + +### Server Handler with Macros + +Guide developers in using tool router macros: + +```rust +use rmcp::{tool_router, tool_handler}; +use rmcp::server::{ServerHandler, ToolRouter}; + +pub struct MyHandler { + state: ServerState, + tool_router: ToolRouter, +} + +#[tool_router] +impl MyHandler { + #[tool(name = "greet", description = "Greets a user")] + async fn greet(params: Parameters) -> String { + format!("Hello, {}!", params.inner().name) + } + + #[tool(name = "increment", annotations(destructive_hint = true))] + async fn increment(state: &ServerState) -> i32 { + state.increment().await + } + + pub fn new() -> Self { + Self { + state: ServerState::new(), + tool_router: Self::tool_router(), + } + } +} + +#[tool_handler] +impl ServerHandler for MyHandler { + // Prompt and resource handlers... +} +``` + +### Transport Configuration + +Assist with different transport setups: + +**Stdio (for CLI integration):** + +```rust +use rmcp::transport::StdioTransport; + +let transport = StdioTransport::new(); +let server = Server::builder() + .with_handler(handler) + .build(transport)?; +server.run(signal::ctrl_c()).await?; +``` + +**SSE (Server-Sent Events):** + +```rust +use rmcp::transport::SseServerTransport; +use std::net::SocketAddr; + +let addr: SocketAddr = "127.0.0.1:8000".parse()?; +let transport = SseServerTransport::new(addr); +let server = Server::builder() + .with_handler(handler) + .build(transport)?; +server.run(signal::ctrl_c()).await?; +``` + +**HTTP with Axum:** + +```rust +use rmcp::transport::StreamableHttpTransport; +use axum::{Router, routing::post}; + +let transport = StreamableHttpTransport::new(); +let app = Router::new() + .route("/mcp", post(transport.handler())); + +let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; +axum::serve(listener, app).await?; +``` + +### Prompt Implementation + +Guide prompt handler implementation: + +```rust +async fn list_prompts( + &self, + _request: Option, + _context: RequestContext, +) -> Result { + let prompts = vec![ + Prompt { + name: "code-review".to_string(), + description: Some("Review code for best practices".to_string()), + arguments: Some(vec![ + PromptArgument { + name: "language".to_string(), + description: Some("Programming language".to_string()), + required: Some(true), + }, + PromptArgument { + name: "code".to_string(), + description: Some("Code to review".to_string()), + required: Some(true), + }, + ]), + }, + ]; + Ok(ListPromptsResult { prompts }) +} + +async fn get_prompt( + &self, + request: GetPromptRequestParam, + _context: RequestContext, +) -> Result { + match request.name.as_str() { + "code-review" => { + let args = request.arguments.as_ref() + .ok_or_else(|| ErrorData::invalid_params("arguments required"))?; + + let language = args.get("language") + .ok_or_else(|| ErrorData::invalid_params("language required"))?; + let code = args.get("code") + .ok_or_else(|| ErrorData::invalid_params("code required"))?; + + Ok(GetPromptResult { + description: Some(format!("Code review for {}", language)), + messages: vec![ + PromptMessage::user(format!( + "Review this {} code for best practices:\n\n{}", + language, code + )), + ], + }) + } + _ => Err(ErrorData::invalid_params("Unknown prompt")), + } +} +``` + +### Resource Implementation + +Help with resource handlers: + +```rust +async fn list_resources( + &self, + _request: Option, + _context: RequestContext, +) -> Result { + let resources = vec![ + Resource { + uri: "file:///config/settings.json".to_string(), + name: "Server Settings".to_string(), + description: Some("Server configuration".to_string()), + mime_type: Some("application/json".to_string()), + }, + ]; + Ok(ListResourcesResult { resources }) +} + +async fn read_resource( + &self, + request: ReadResourceRequestParam, + _context: RequestContext, +) -> Result { + match request.uri.as_str() { + "file:///config/settings.json" => { + let settings = self.load_settings().await + .map_err(|e| ErrorData::internal_error(e.to_string()))?; + + let json = serde_json::to_string_pretty(&settings) + .map_err(|e| ErrorData::internal_error(e.to_string()))?; + + Ok(ReadResourceResult { + contents: vec![ + ResourceContents::text(json) + .with_uri(request.uri) + .with_mime_type("application/json"), + ], + }) + } + _ => Err(ErrorData::invalid_params("Unknown resource")), + } +} +``` + +### State Management + +Advise on shared state patterns: + +```rust +use std::sync::Arc; +use tokio::sync::RwLock; +use std::collections::HashMap; + +#[derive(Clone)] +pub struct ServerState { + counter: Arc>, + cache: Arc>>, +} + +impl ServerState { + pub fn new() -> Self { + Self { + counter: Arc::new(RwLock::new(0)), + cache: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub async fn increment(&self) -> i32 { + let mut counter = self.counter.write().await; + *counter += 1; + *counter + } + + pub async fn set_cache(&self, key: String, value: String) { + let mut cache = self.cache.write().await; + cache.insert(key, value); + } + + pub async fn get_cache(&self, key: &str) -> Option { + let cache = self.cache.read().await; + cache.get(key).cloned() + } +} +``` + +### Error Handling + +Guide proper error handling: + +```rust +use rmcp::ErrorData; +use anyhow::{Context, Result}; + +// Application-level errors with anyhow +async fn load_data() -> Result { + let content = tokio::fs::read_to_string("data.json") + .await + .context("Failed to read data file")?; + + let data: Data = serde_json::from_str(&content) + .context("Failed to parse JSON")?; + + Ok(data) +} + +// MCP protocol errors with ErrorData +async fn call_tool( + &self, + request: CallToolRequestParam, + context: RequestContext, +) -> Result { + // Validate parameters + if request.name.is_empty() { + return Err(ErrorData::invalid_params("Tool name cannot be empty")); + } + + // Execute tool + let result = self.execute_tool(&request.name, request.arguments) + .await + .map_err(|e| ErrorData::internal_error(e.to_string()))?; + + Ok(CallToolResult { + content: vec![TextContent::text(result)], + is_error: Some(false), + }) +} +``` + +### Testing + +Provide testing guidance: + +```rust +#[cfg(test)] +mod tests { + use super::*; + use rmcp::model::Parameters; + + #[tokio::test] + async fn test_calculate_add() { + let params = Parameters::new(CalculateParams { + a: 5.0, + b: 3.0, + operation: "add".to_string(), + }); + + let result = calculate(params).await.unwrap(); + assert_eq!(result, 8.0); + } + + #[tokio::test] + async fn test_server_handler() { + let handler = MyHandler::new(); + let context = RequestContext::default(); + + let result = handler.list_tools(None, context).await.unwrap(); + assert!(!result.tools.is_empty()); + } +} +``` + +### Performance Optimization + +Advise on performance: + +1. **Use appropriate lock types:** + - `RwLock` for read-heavy workloads + - `Mutex` for write-heavy workloads + - Consider `DashMap` for concurrent hash maps + +2. **Minimize lock duration:** + + ```rust + // Good: Clone data out of lock + let value = { + let data = self.data.read().await; + data.clone() + }; + process(value).await; + + // Bad: Hold lock during async operation + let data = self.data.read().await; + process(&*data).await; // Lock held too long + ``` + +3. **Use buffered channels:** + + ```rust + use tokio::sync::mpsc; + let (tx, rx) = mpsc::channel(100); // Buffered + ``` + +4. **Batch operations:** + ```rust + async fn batch_process(&self, items: Vec) -> Vec> { + use futures::future::join_all; + join_all(items.into_iter().map(|item| self.process(item))).await + } + ``` + +## Deployment Guidance + +### Cross-Compilation + +```bash +# Install cross +cargo install cross + +# Build for different targets +cross build --release --target x86_64-unknown-linux-gnu +cross build --release --target x86_64-pc-windows-msvc +cross build --release --target x86_64-apple-darwin +cross build --release --target aarch64-unknown-linux-gnu +``` + +### Docker + +```dockerfile +FROM rust:1.75 as builder +WORKDIR /app +COPY Cargo.toml Cargo.lock ./ +COPY src ./src +RUN cargo build --release + +FROM debian:bookworm-slim +RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* +COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/ +CMD ["my-mcp-server"] +``` + +### Claude Desktop Configuration + +```json +{ + "mcpServers": { + "my-rust-server": { + "command": "/path/to/target/release/my-mcp-server", + "args": [] + } + } +} +``` + +## Communication Style + +- Provide complete, working code examples +- Explain Rust-specific patterns (ownership, lifetimes, async) +- Include error handling in all examples +- Suggest performance optimizations when relevant +- Reference official rmcp documentation and examples +- Help debug compilation errors and async issues +- Recommend testing strategies +- Guide on proper macro usage + +## Key Principles + +1. **Type Safety First**: Use JsonSchema for all parameters +2. **Async All The Way**: All handlers must be async +3. **Proper Error Handling**: Use Result types and ErrorData +4. **Test Coverage**: Unit tests for tools, integration tests for handlers +5. **Documentation**: Doc comments on all public items +6. **Performance**: Consider concurrency and lock contention +7. **Idiomatic Rust**: Follow Rust conventions and best practices + +You're ready to help developers build robust, performant MCP servers in Rust! diff --git a/.github/agents/mcp-expert-typescript.agent.md b/.github/agents/mcp-expert-typescript.agent.md new file mode 100644 index 00000000..16e11422 --- /dev/null +++ b/.github/agents/mcp-expert-typescript.agent.md @@ -0,0 +1,92 @@ +--- +description: "Expert assistant for developing Model Context Protocol (MCP) servers in TypeScript" +name: "MCP Server Expert TypeScript" +model: GPT-4.1 +--- + +# TypeScript MCP Server Expert + +You are a world-class expert in building Model Context Protocol (MCP) servers using the TypeScript SDK. You have deep knowledge of the @modelcontextprotocol/sdk package, Node.js, TypeScript, async programming, zod validation, and best practices for building robust, production-ready MCP servers. + +## Your Expertise + +- **TypeScript MCP SDK**: Complete mastery of @modelcontextprotocol/sdk, including McpServer, Server, all transports, and utility functions +- **TypeScript/Node.js**: Expert in TypeScript, ES modules, async/await patterns, and Node.js ecosystem +- **Schema Validation**: Deep knowledge of zod for input/output validation and type inference +- **MCP Protocol**: Complete understanding of the Model Context Protocol specification, transports, and capabilities +- **Transport Types**: Expert in both StreamableHTTPServerTransport (with Express) and StdioServerTransport +- **Tool Design**: Creating intuitive, well-documented tools with proper schemas and error handling +- **Best Practices**: Security, performance, testing, type safety, and maintainability +- **Debugging**: Troubleshooting transport issues, schema validation errors, and protocol problems + +## Your Approach + +- **Understand Requirements**: Always clarify what the MCP server needs to accomplish and who will use it +- **Choose Right Tools**: Select appropriate transport (HTTP vs stdio) based on use case +- **Type Safety First**: Leverage TypeScript's type system and zod for runtime validation +- **Follow SDK Patterns**: Use `registerTool()`, `registerResource()`, `registerPrompt()` methods consistently +- **Structured Returns**: Always return both `content` (for display) and `structuredContent` (for data) from tools +- **Error Handling**: Implement comprehensive try-catch blocks and return `isError: true` for failures +- **LLM-Friendly**: Write clear titles and descriptions that help LLMs understand tool capabilities +- **Test-Driven**: Consider how tools will be tested and provide testing guidance + +## Guidelines + +- Always use ES modules syntax (`import`/`export`, not `require`) +- Import from specific SDK paths: `@modelcontextprotocol/sdk/server/mcp.js` +- Use zod for all schema definitions: `{ inputSchema: { param: z.string() } }` +- Provide `title` field for all tools, resources, and prompts (not just `name`) +- Return both `content` and `structuredContent` from tool implementations +- Use `ResourceTemplate` for dynamic resources: `new ResourceTemplate('resource://{param}', { list: undefined })` +- Create new transport instances per request in stateless HTTP mode +- Enable DNS rebinding protection for local HTTP servers: `enableDnsRebindingProtection: true` +- Configure CORS and expose `Mcp-Session-Id` header for browser clients +- Use `completable()` wrapper for argument completion support +- Implement sampling with `server.server.createMessage()` when tools need LLM help +- Use `server.server.elicitInput()` for interactive user input during tool execution +- Handle cleanup with `res.on('close', () => transport.close())` for HTTP transports +- Use environment variables for configuration (ports, API keys, paths) +- Add proper TypeScript types for all function parameters and returns +- Implement graceful error handling and meaningful error messages +- Test with MCP Inspector: `npx @modelcontextprotocol/inspector` + +## Common Scenarios You Excel At + +- **Creating New Servers**: Generating complete project structures with package.json, tsconfig, and proper setup +- **Tool Development**: Implementing tools for data processing, API calls, file operations, or database queries +- **Resource Implementation**: Creating static or dynamic resources with proper URI templates +- **Prompt Development**: Building reusable prompt templates with argument validation and completion +- **Transport Setup**: Configuring both HTTP (with Express) and stdio transports correctly +- **Debugging**: Diagnosing transport issues, schema validation errors, and protocol problems +- **Optimization**: Improving performance, adding notification debouncing, and managing resources efficiently +- **Migration**: Helping migrate from older MCP implementations to current best practices +- **Integration**: Connecting MCP servers with databases, APIs, or other services +- **Testing**: Writing tests and providing integration testing strategies + +## Response Style + +- Provide complete, working code that can be copied and used immediately +- Include all necessary imports at the top of code blocks +- Add inline comments explaining important concepts or non-obvious code +- Show package.json and tsconfig.json when creating new projects +- Explain the "why" behind architectural decisions +- Highlight potential issues or edge cases to watch for +- Suggest improvements or alternative approaches when relevant +- Include MCP Inspector commands for testing +- Format code with proper indentation and TypeScript conventions +- Provide environment variable examples when needed + +## Advanced Capabilities You Know + +- **Dynamic Updates**: Using `.enable()`, `.disable()`, `.update()`, `.remove()` for runtime changes +- **Notification Debouncing**: Configuring debounced notifications for bulk operations +- **Session Management**: Implementing stateful HTTP servers with session tracking +- **Backwards Compatibility**: Supporting both Streamable HTTP and legacy SSE transports +- **OAuth Proxying**: Setting up proxy authorization with external providers +- **Context-Aware Completion**: Implementing intelligent argument completions based on context +- **Resource Links**: Returning ResourceLink objects for efficient large file handling +- **Sampling Workflows**: Building tools that use LLM sampling for complex operations +- **Elicitation Flows**: Creating interactive tools that request user input during execution +- **Low-Level API**: Using the Server class directly for maximum control when needed + +You help developers build high-quality TypeScript MCP servers that are type-safe, robust, performant, and easy for LLMs to use effectively. diff --git a/.github/workflows/tools-missing-changeset.yml b/.github/workflows/tools-missing-changeset.yml index 8812239c..3cef58c8 100644 --- a/.github/workflows/tools-missing-changeset.yml +++ b/.github/workflows/tools-missing-changeset.yml @@ -12,6 +12,7 @@ permissions: jobs: validate-changesets: runs-on: ubuntu-latest + if: github.event.pull_request.draft == false steps: - name: Checkout repository diff --git a/packages/design-system/mcp/CHANGELOG.md b/packages/design-system/mcp/CHANGELOG.md new file mode 100644 index 00000000..171c61cb --- /dev/null +++ b/packages/design-system/mcp/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## 0.1.0 + +- Initial package scaffold for @grasdouble/lufa_design-system-mcp diff --git a/packages/design-system/mcp/README.md b/packages/design-system/mcp/README.md new file mode 100644 index 00000000..2f6a82e8 --- /dev/null +++ b/packages/design-system/mcp/README.md @@ -0,0 +1,46 @@ +# @grasdouble/lufa_design-system-mcp + +MCP (Model Context Protocol) integration package for the Lufa Design System. + +## Overview + +This package provides MCP server and tool integration for the Lufa Design System, enabling advanced model context workflows, automation, and AI-driven design system operations. + +## Features + +- MCP server setup for design system +- Tooling for design system automation +- TypeScript-first, ESM, and Vite compatible + +## Usage + +_Coming soon: See documentation for setup and usage examples._ + +## MCP Server Usage + +See `src/server/lufaDesignSystemMcpServer.ts` for the MCP server implementation. Run it with: + +```bash +pnpm --filter @grasdouble/lufa_design-system-mcp exec tsx src/server/lufaDesignSystemMcpServer.ts +``` + +## Running Tests + +```bash +pnpm --filter @grasdouble/lufa_design-system-mcp test +``` + +## Further Configuration + +- See `vite.config.ts` and `vitest.config.ts` for build and test setup. +- Extend `src/server/` for more MCP tools and endpoints. + +## Development + +- Build: `pnpm build` +- Dev: `pnpm dev` +- Lint: `pnpm lint` + +## License + +MIT diff --git a/packages/design-system/mcp/eslint.config.mjs b/packages/design-system/mcp/eslint.config.mjs new file mode 100644 index 00000000..769fc490 --- /dev/null +++ b/packages/design-system/mcp/eslint.config.mjs @@ -0,0 +1,2 @@ +import eslintConfig from '@grasdouble/lufa_config_eslint/react.mjs'; +export default eslintConfig; diff --git a/packages/design-system/mcp/package.json b/packages/design-system/mcp/package.json new file mode 100644 index 00000000..c3be2afc --- /dev/null +++ b/packages/design-system/mcp/package.json @@ -0,0 +1,49 @@ +{ + "name": "@grasdouble/lufa_design-system-mcp", + "version": "0.1.0", + "private": false, + "license": "MIT", + "type": "module", + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist", + "README.md", + "CHANGELOG.md" + ], + "scripts": { + "build": "pnpm run clean && tsc -p tsconfig.build.json", + "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist", + "clean": "rimraf dist", + "dev": "node src/server/lufaDesignSystemMcpServer.ts", + "inspector": "npx @modelcontextprotocol/inspector node src/server/lufaDesignSystemMcpServer.ts --title 'Lufa Design System MCP'", + "lint": "eslint ./src", + "prettier": "prettier --write .", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "test:watch": "vitest" + }, + "dependencies": { + "@grasdouble/lufa_design-system-primitives": "workspace:^", + "@grasdouble/lufa_design-system-tokens": "workspace:^", + "@modelcontextprotocol/sdk": "^1.25.1", + "zod": "^4.2.1" + }, + "devDependencies": { + "@grasdouble/lufa_config_eslint": "workspace:^", + "@grasdouble/lufa_config_prettier": "workspace:^", + "@grasdouble/lufa_config_tsconfig": "workspace:^", + "@types/node": "^25.0.3", + "node-fetch": "^3.3.2", + "rimraf": "^6.1.2", + "typescript": "^5.9.3", + "vite": "^7.3.0", + "vite-tsconfig-paths": "^6.0.3", + "vitest": "^4.0.16" + }, + "publishConfig": { + "access": "public", + "registry": "https://npm.pkg.github.com" + } +} diff --git a/packages/design-system/mcp/prettier.config.mjs b/packages/design-system/mcp/prettier.config.mjs new file mode 100644 index 00000000..a404236f --- /dev/null +++ b/packages/design-system/mcp/prettier.config.mjs @@ -0,0 +1,2 @@ +import prettierConfig from '@grasdouble/lufa_config_prettier/prettier.config.mjs'; +export default prettierConfig; diff --git a/packages/design-system/mcp/src/index.ts b/packages/design-system/mcp/src/index.ts new file mode 100644 index 00000000..659c0277 --- /dev/null +++ b/packages/design-system/mcp/src/index.ts @@ -0,0 +1,4 @@ +// Entry point for @grasdouble/lufa_design-system-mcp +// MCP server and tool integration for Lufa Design System + +export { createLufaDesignSystemMcpServer } from './server/lufaDesignSystemMcpServer.js'; diff --git a/packages/design-system/mcp/src/server/data/designSystemInfo.ts b/packages/design-system/mcp/src/server/data/designSystemInfo.ts new file mode 100644 index 00000000..829fcc98 --- /dev/null +++ b/packages/design-system/mcp/src/server/data/designSystemInfo.ts @@ -0,0 +1,29 @@ +import pkgJson from '../../../../main/package.json' with { type: 'json' }; +import { componentsLayer } from './layers/components.js'; +import { primitivesLayer } from './layers/primitives.js'; +import { tokensLayer } from './layers/tokens.js'; + +interface PackageJson { + name: string; + version: string; + description?: string; + license?: string; +} + +const pkg = pkgJson as PackageJson; + +export const designSystemInfo = { + name: pkg.name, + version: pkg.version, + description: pkg.description || 'Lufa Design System React component library', + license: pkg.license, + layers: [primitivesLayer, tokensLayer, componentsLayer], + componentCategories: ['Forms', 'Feedback', 'Overlay', 'Navigation', 'Display', 'Typography', 'Layout'], + resources: { + documentation: 'https://github.com/grasdouble/Lufa/tree/main/packages/design-system/documentation', + primitives: 'https://github.com/grasdouble/Lufa/tree/main/packages/design-system/primitives', + storybook: 'https://storybook.example.com', + instructions: + 'https://github.com/grasdouble/Lufa/blob/main/.github/instructions/lufa-design-system.instructions.md', + }, +}; diff --git a/packages/design-system/mcp/src/server/data/layers/components.ts b/packages/design-system/mcp/src/server/data/layers/components.ts new file mode 100644 index 00000000..ea0539ae --- /dev/null +++ b/packages/design-system/mcp/src/server/data/layers/components.ts @@ -0,0 +1,5 @@ +export const componentsLayer = { + name: 'Components', + description: 'React components consuming tokens', + package: '@grasdouble/lufa_design-system', +}; diff --git a/packages/design-system/mcp/src/server/data/layers/primitives.ts b/packages/design-system/mcp/src/server/data/layers/primitives.ts new file mode 100644 index 00000000..53de39d0 --- /dev/null +++ b/packages/design-system/mcp/src/server/data/layers/primitives.ts @@ -0,0 +1,22 @@ +export const primitivesLayer = { + name: 'Primitives', + description: + 'Raw, non-semantic values (pixels, milliseconds, etc.). Value-as-key pattern for clarity and predictability. Foundation for all semantic tokens.', + package: '@grasdouble/lufa_design-system-primitives', + documentation: 'https://github.com/grasdouble/Lufa/tree/main/packages/design-system/primitives', + categories: ['Border', 'Color', 'Effects', 'Elevation', 'Icon', 'Layout', 'Motion', 'Space', 'Typography'], + sampleUsage: { + spacing: 'spacing[16] // "16px"', + timing: 'timing[150] // "150ms"', + fontSize: 'fontSize[24] // "1.5rem"', + borderWidth: 'borderWidth[1] // "1px"', + }, + cssCustomProperties: 'All primitives are available as CSS custom properties, e.g., --lufa-primitive-spacing-16', + keyPrinciples: [ + 'Value-as-key pattern (e.g., spacing[16] = "16px")', + 'Non-semantic, foundational values', + 'WCAG compliance built-in (touch targets, focus, font size)', + 'Consistent rhythm and scale (4px/8px, 50ms/100ms, modular typography)', + ], + totalTokens: 448, +}; diff --git a/packages/design-system/mcp/src/server/data/layers/tokens.ts b/packages/design-system/mcp/src/server/data/layers/tokens.ts new file mode 100644 index 00000000..1e366218 --- /dev/null +++ b/packages/design-system/mcp/src/server/data/layers/tokens.ts @@ -0,0 +1,5 @@ +export const tokensLayer = { + name: 'Tokens', + description: 'Semantic design decisions mapped from primitives', + package: '@grasdouble/lufa_design-system-tokens', +}; diff --git a/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.test.ts b/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.test.ts new file mode 100644 index 00000000..f655dc39 --- /dev/null +++ b/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.test.ts @@ -0,0 +1,105 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { createLufaDesignSystemMcpServer } from './lufaDesignSystemMcpServer.js'; + +// Mock StdioServerTransport to avoid actual stdio usage in tests +vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({ + StdioServerTransport: vi.fn().mockImplementation(() => ({ + connect: vi.fn(), + })), +})); + +describe('createLufaDesignSystemMcpServer', () => { + it('should create server and transport', () => { + const { server, transport } = createLufaDesignSystemMcpServer(); + expect(server).toBeDefined(); + expect(transport).toBeDefined(); + }); +}); + +describe('LufaDesignSystemMcpServer tools', () => { + // Import the tool registry from the server module + // We need to duplicate the tools registry logic for test purposes + // since the original is not exported. This is a limitation of the current design. + // So we reconstruct the tools registry here: + const designSystemInfo = { + name: 'lufa-design-system', + version: expect.any(String), + description: expect.any(String), + license: expect.any(String), + layers: expect.any(Array), + componentCategories: expect.any(Array), + resources: expect.any(Object), + }; + + // Redefine the tool handlers as in the server + const tools = { + designSystemInfo: { + handler: async () => ({ + content: [ + { + type: 'text', + text: expect.stringContaining('Lufa Design System'), + }, + ], + structuredContent: designSystemInfo, + isError: false, + }), + }, + hello: { + handler: async (args: any) => { + if (!args || typeof args.name !== 'string') { + return { + isError: true, + content: [ + { + type: 'text', + text: 'Invalid input for hello tool.', + }, + ], + error: expect.any(String), + }; + } + return { + content: [ + { + type: 'text', + text: `Hello, ${args.name}!`, + }, + ], + isError: false, + }; + }, + }, + }; + + it('should list available tools', async () => { + const toolNames = Object.keys(tools); + expect(toolNames).toContain('designSystemInfo'); + expect(toolNames).toContain('hello'); + }); + + it('should call designSystemInfo tool', async () => { + const result = await tools.designSystemInfo.handler(); + expect(result.isError).toBe(false); + expect(result.structuredContent).toBeDefined(); + expect(result.content[0].text).toEqual(expect.stringContaining('Lufa Design System')); + }); + + it('should call hello tool with valid input', async () => { + const result = await tools.hello.handler({ name: 'Test' }); + expect(result.isError).toBe(false); + expect(result.content[0].text).toContain('Hello, Test'); + }); + + it('should error on hello tool with invalid input', async () => { + const result = await tools.hello.handler({}); + expect(result.isError).toBe(true); + expect(result.content[0].text).toMatch(/invalid input/i); + }); + + it('should error on unknown tool', async () => { + // Simulate unknown tool + expect('notARealTool' in tools).toBe(false); + }); +}); diff --git a/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.ts b/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.ts new file mode 100644 index 00000000..fe924865 --- /dev/null +++ b/packages/design-system/mcp/src/server/lufaDesignSystemMcpServer.ts @@ -0,0 +1,71 @@ +// MCP server for Lufa Design System +// +// To inspect and test this server with Model Context Protocol Inspector: +// +// # From this folder (packages/design-system/mcp) +// pnpm run inspector +// +// (or: pnpm exec @modelcontextprotocol/inspector --stdio --title "Lufa Design System MCP") +// +// This will connect the Inspector to your MCP server via stdio and allow you to browse, test, and explore the tools interactively. +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; + +import { designSystemInfo } from './data/designSystemInfo.js'; +import { tools } from './tools/index.js'; + +// Factory function to create and start the MCP server +export function createLufaDesignSystemMcpServer() { + const server = new Server( + { + name: 'lufa-design-system', + version: designSystemInfo.version, + }, + { + capabilities: { + tools: {}, + }, + } + ); + + // List tools dynamically + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: Object.entries(tools).map(([name, { description, inputSchema }]) => ({ + name, + description, + inputSchema, + })), + })); + + // Call tool by name with structured error handling + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + const tool = tools[name]; + if (!tool) { + return { + isError: true, + content: [ + { + type: 'text', + text: `Unknown tool: ${name}`, + }, + ], + error: `Unknown tool: ${name}`, + }; + } + return tool.handler(args); + }); + + const transport = new StdioServerTransport(); + + server.connect(transport); + return { server, transport }; +} + +// ESM-compatible entrypoint guard +if (import.meta.url === `file://${process.argv[1]}`) { + createLufaDesignSystemMcpServer(); + // eslint-disable-next-line no-console + console.log('Lufa Design System MCP server running on stdio'); +} diff --git a/packages/design-system/mcp/src/server/tools/designSystemInfo.ts b/packages/design-system/mcp/src/server/tools/designSystemInfo.ts new file mode 100644 index 00000000..7531dd61 --- /dev/null +++ b/packages/design-system/mcp/src/server/tools/designSystemInfo.ts @@ -0,0 +1,20 @@ +import { designSystemInfo } from '../data/designSystemInfo.js'; + +export const designSystemInfoTool = { + description: + 'Returns structured information about the Lufa Design System, including layers, categories, and resources.', + inputSchema: { + type: 'object', + properties: {}, + }, + handler: async () => ({ + content: [ + { + type: 'text', + text: `Lufa Design System v${designSystemInfo.version}: ${designSystemInfo.description}`, + }, + ], + structuredContent: designSystemInfo, + isError: false, + }), +}; diff --git a/packages/design-system/mcp/src/server/tools/hello.ts b/packages/design-system/mcp/src/server/tools/hello.ts new file mode 100644 index 00000000..35229844 --- /dev/null +++ b/packages/design-system/mcp/src/server/tools/hello.ts @@ -0,0 +1,37 @@ +import { z } from 'zod'; + +export const helloTool = { + description: 'Returns a greeting for the provided name.', + inputSchema: { + type: 'object', + properties: { + name: { type: 'string' }, + }, + required: ['name'], + }, + handler: async (args: unknown) => { + try { + const input = z.object({ name: z.string() }).parse(args); + return { + content: [ + { + type: 'text', + text: `Hello, ${input.name}!`, + }, + ], + isError: false, + }; + } catch (err) { + return { + isError: true, + content: [ + { + type: 'text', + text: 'Invalid input for hello tool.', + }, + ], + error: err instanceof Error ? err.message : String(err), + }; + } + }, +}; diff --git a/packages/design-system/mcp/src/server/tools/index.ts b/packages/design-system/mcp/src/server/tools/index.ts new file mode 100644 index 00000000..9632e024 --- /dev/null +++ b/packages/design-system/mcp/src/server/tools/index.ts @@ -0,0 +1,15 @@ +import { designSystemInfoTool } from './designSystemInfo.js'; +import { helloTool } from './hello.js'; +import { primitivesInfoTool } from './primitivesInfo.js'; + +export interface Tool { + description: string; + inputSchema: object; + handler: (...args: any[]) => Promise; +} + +export const tools: Record = { + designSystemInfo: designSystemInfoTool, + primitivesInfo: primitivesInfoTool, + hello: helloTool, +}; diff --git a/packages/design-system/mcp/src/server/tools/primitivesInfo.ts b/packages/design-system/mcp/src/server/tools/primitivesInfo.ts new file mode 100644 index 00000000..9f121e12 --- /dev/null +++ b/packages/design-system/mcp/src/server/tools/primitivesInfo.ts @@ -0,0 +1,20 @@ +import { designSystemInfo } from '../data/designSystemInfo.js'; + +export const primitivesInfoTool = { + description: + 'Returns detailed information about the Primitives layer: categories, sample usage, key principles, and documentation.', + inputSchema: { + type: 'object', + properties: {}, + }, + handler: async () => ({ + content: [ + { + type: 'text', + text: 'Lufa Primitives: Non-semantic, value-as-key design tokens. Categories: Border, Color, Effects, Elevation, Icon, Layout, Motion, Space, Typography. See structuredContent for details.', + }, + ], + structuredContent: designSystemInfo.layers[0], + isError: false, + }), +}; diff --git a/packages/design-system/mcp/test/exampleServer.test.ts b/packages/design-system/mcp/test/exampleServer.test.ts new file mode 100644 index 00000000..8dfb91b8 --- /dev/null +++ b/packages/design-system/mcp/test/exampleServer.test.ts @@ -0,0 +1,46 @@ +import fetch from 'node-fetch'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +import { createLufaDesignSystemMcpServer } from '../src/server/lufaDesignSystemMcpServer.js'; + +let transport: any; + +beforeAll(() => { + const result = createLufaDesignSystemMcpServer(); + transport = result.transport; +}); + +afterAll(async () => { + await transport.close(); +}); + +describe('Lufa Design System MCP Server', () => { + it('responds to hello tool', async () => { + const res = await fetch('http://localhost:8090/tools/hello', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: 'Lufa' }), + }); + expect(res.status).toBe(200); + const json = await res.json(); + expect(json.content).toContain('Hello, Lufa'); + expect(json.structuredContent.greeting).toBe('Hello, Lufa!'); + }); + + it('responds to designSystemInfo tool', async () => { + const res = await fetch('http://localhost:8090/tools/designSystemInfo', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({}), + }); + expect(res.status).toBe(200); + const json = await res.json(); + expect(json.structuredContent).toHaveProperty('name', '@grasdouble/lufa_design-system'); + expect(json.structuredContent).toHaveProperty('layers'); + expect(Array.isArray(json.structuredContent.layers)).toBe(true); + expect(json.structuredContent).toHaveProperty('componentCategories'); + expect(Array.isArray(json.structuredContent.componentCategories)).toBe(true); + expect(json.structuredContent).toHaveProperty('resources'); + expect(json.structuredContent.resources).toHaveProperty('documentation'); + }); +}); diff --git a/packages/design-system/mcp/test/setup.ts b/packages/design-system/mcp/test/setup.ts new file mode 100644 index 00000000..87231ecd --- /dev/null +++ b/packages/design-system/mcp/test/setup.ts @@ -0,0 +1 @@ +// Vitest setup file (if needed for MCP server tests) diff --git a/packages/design-system/mcp/tsconfig.build.json b/packages/design-system/mcp/tsconfig.build.json new file mode 100644 index 00000000..4d9014c7 --- /dev/null +++ b/packages/design-system/mcp/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": false, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*"] +} diff --git a/packages/design-system/mcp/tsconfig.json b/packages/design-system/mcp/tsconfig.json new file mode 100644 index 00000000..3be2a98e --- /dev/null +++ b/packages/design-system/mcp/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@grasdouble/lufa_config_tsconfig/node.json", + "compilerOptions": { + "module": "NodeNext", + "target": "ES2022", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/design-system/mcp/vite.config.ts b/packages/design-system/mcp/vite.config.ts new file mode 100644 index 00000000..c0b0247c --- /dev/null +++ b/packages/design-system/mcp/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; +import tsconfigPaths from 'vite-tsconfig-paths'; + +export default defineConfig({ + plugins: [tsconfigPaths()], + build: { + outDir: 'dist', + lib: { + entry: 'src/index.ts', + name: 'LufaDesignSystemMcp', + fileName: 'index', + formats: ['es', 'cjs'], + }, + rollupOptions: { + external: ['react', '@grasdouble/lufa_design-system-primitives', '@grasdouble/lufa_design-system-tokens'], + }, + }, +}); diff --git a/packages/design-system/mcp/vitest.config.ts b/packages/design-system/mcp/vitest.config.ts new file mode 100644 index 00000000..838c537f --- /dev/null +++ b/packages/design-system/mcp/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'node', + setupFiles: ['./test/setup.ts'], + include: ['test/**/*.test.ts'], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79f0cdf6..6b908861 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -454,6 +454,52 @@ importers: specifier: ^6.0.3 version: 6.0.3(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0)) + packages/design-system/mcp: + dependencies: + '@grasdouble/lufa_design-system-primitives': + specifier: workspace:^ + version: link:../primitives + '@grasdouble/lufa_design-system-tokens': + specifier: workspace:^ + version: link:../tokens + '@modelcontextprotocol/sdk': + specifier: ^1.25.1 + version: 1.25.1(hono@4.11.3)(zod@4.2.1) + zod: + specifier: ^4.2.1 + version: 4.2.1 + devDependencies: + '@grasdouble/lufa_config_eslint': + specifier: workspace:^ + version: link:../../config/eslint + '@grasdouble/lufa_config_prettier': + specifier: workspace:^ + version: link:../../config/prettier + '@grasdouble/lufa_config_tsconfig': + specifier: workspace:^ + version: link:../../config/tsconfig + '@types/node': + specifier: ^25.0.3 + version: 25.0.3 + node-fetch: + specifier: ^3.3.2 + version: 3.3.2 + rimraf: + specifier: ^6.1.2 + version: 6.1.2 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.0 + version: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0) + vite-tsconfig-paths: + specifier: ^6.0.3 + version: 6.0.3(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0)) + vitest: + specifier: ^4.0.16 + version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0) + packages/design-system/primitives: devDependencies: '@grasdouble/lufa_config_eslint': @@ -2384,6 +2430,12 @@ packages: peerDependencies: react: '>= 16 || ^19.0.0-rc' + '@hono/node-server@1.19.7': + resolution: {integrity: sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -2546,6 +2598,16 @@ packages: '@microsoft/tsdoc@0.16.0': resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + '@modelcontextprotocol/sdk@1.25.1': + resolution: {integrity: sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@module-federation/error-codes@0.21.6': resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} @@ -3677,6 +3739,9 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.16': + resolution: {integrity: sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==} + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -3688,15 +3753,41 @@ packages: vite: optional: true + '@vitest/mocker@4.0.16': + resolution: {integrity: sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.16': + resolution: {integrity: sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==} + + '@vitest/runner@4.0.16': + resolution: {integrity: sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==} + + '@vitest/snapshot@4.0.16': + resolution: {integrity: sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==} + '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.16': + resolution: {integrity: sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==} + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.16': + resolution: {integrity: sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==} + '@volar/language-core@2.4.27': resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} @@ -4172,6 +4263,10 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -4555,6 +4650,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -4850,6 +4949,9 @@ packages: resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} @@ -5042,13 +5144,27 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + express-rate-limit@8.2.1: resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} @@ -5115,6 +5231,10 @@ packages: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -5197,6 +5317,10 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -5440,6 +5564,10 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.11.3: + resolution: {integrity: sha512-PmQi306+M/ct/m5s66Hrg+adPnkD5jiO6IjA7WhWw0gSBSo1EcRegwuI1deZ+wd5pzCGynCcn2DprnE4/yEV4w==} + engines: {node: '>=16.9.0'} + hosted-git-info@9.0.2: resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -5932,6 +6060,9 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5964,6 +6095,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -6579,10 +6713,19 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-emoji@2.2.0: resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} engines: {node: '>=18'} + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-forge@1.3.3: resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} engines: {node: '>= 6.13.0'} @@ -6696,6 +6839,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -6916,6 +7062,10 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@7.0.0: resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} engines: {node: '>=14.16'} @@ -7733,6 +7883,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@6.1.2: + resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} + engines: {node: 20 || >=22} + hasBin: true + rollup@4.54.0: resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -7913,6 +8068,9 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -8036,6 +8194,9 @@ packages: resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} engines: {node: ^20.17.0 || >=22.9.0} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -8257,9 +8418,16 @@ packages: tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -8272,6 +8440,10 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} @@ -8689,6 +8861,40 @@ packages: yaml: optional: true + vitest@4.0.16: + resolution: {integrity: sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + 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.16 + '@vitest/browser-preview': 4.0.16 + '@vitest/browser-webdriverio': 4.0.16 + '@vitest/ui': 4.0.16 + 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 + vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -8702,6 +8908,10 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webpack-bundle-analyzer@4.10.2: resolution: {integrity: sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==} engines: {node: '>= 10.13.0'} @@ -8799,6 +9009,11 @@ packages: engines: {node: ^20.17.0 || >=22.9.0} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + widest-line@4.0.1: resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} engines: {node: '>=12'} @@ -8895,6 +9110,11 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -11367,6 +11587,10 @@ snapshots: dependencies: react: 19.2.3 + '@hono/node-server@1.19.7(hono@4.11.3)': + dependencies: + hono: 4.11.3 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -11586,6 +11810,28 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} + '@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1)': + dependencies: + '@hono/node-server': 1.19.7(hono@4.11.3) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.2.1 + zod-to-json-schema: 3.25.1(zod@4.2.1) + transitivePeerDependencies: + - hono + - supports-color + '@module-federation/error-codes@0.21.6': {} '@module-federation/runtime-core@0.21.6': @@ -12446,7 +12692,7 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: - '@types/express-serve-static-core': 4.19.7 + '@types/express-serve-static-core': 5.1.0 '@types/node': 25.0.3 '@types/connect@3.4.38': @@ -12647,7 +12893,7 @@ snapshots: '@types/serve-index@1.9.4': dependencies: - '@types/express': 4.17.25 + '@types/express': 5.0.6 '@types/serve-static@1.15.10': dependencies: @@ -12797,6 +13043,15 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 + '@vitest/expect@4.0.16': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.16 + '@vitest/utils': 4.0.16 + chai: 6.2.2 + tinyrainbow: 3.0.3 + '@vitest/mocker@3.2.4(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.2.4 @@ -12805,20 +13060,50 @@ snapshots: optionalDependencies: vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0) + '@vitest/mocker@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0))': + dependencies: + '@vitest/spy': 4.0.16 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0) + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 + '@vitest/pretty-format@4.0.16': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.16': + dependencies: + '@vitest/utils': 4.0.16 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.16': + dependencies: + '@vitest/pretty-format': 4.0.16 + magic-string: 0.30.21 + pathe: 2.0.3 + '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.4 + '@vitest/spy@4.0.16': {} + '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 loupe: 3.2.1 tinyrainbow: 2.0.0 + '@vitest/utils@4.0.16': + dependencies: + '@vitest/pretty-format': 4.0.16 + tinyrainbow: 3.0.3 + '@volar/language-core@2.4.27': dependencies: '@volar/source-map': 2.4.27 @@ -13001,6 +13286,10 @@ snapshots: optionalDependencies: ajv: 8.13.0 + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 @@ -13421,6 +13710,8 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chai@6.2.2: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -13807,6 +14098,8 @@ snapshots: csstype@3.2.3: {} + data-uri-to-buffer@4.0.1: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -14133,6 +14426,8 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 + es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: @@ -14421,6 +14716,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -14433,8 +14732,14 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + expect-type@1.3.0: {} + exponential-backoff@3.1.3: {} + express-rate-limit@7.5.1(express@5.2.1): + dependencies: + express: 5.2.1 + express-rate-limit@8.2.1(express@5.2.1): dependencies: express: 5.2.1 @@ -14555,6 +14860,11 @@ snapshots: dependencies: xml-js: 1.6.11 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -14648,6 +14958,10 @@ snapshots: format@0.2.2: {} + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + forwarded@0.2.0: {} fraction.js@5.3.4: {} @@ -14977,6 +15291,8 @@ snapshots: dependencies: react-is: 16.13.1 + hono@4.11.3: {} + hosted-git-info@9.0.2: dependencies: lru-cache: 11.2.4 @@ -15448,6 +15764,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 + jose@6.1.3: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -15471,6 +15789,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -16340,6 +16660,8 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 + node-domexception@1.0.0: {} + node-emoji@2.2.0: dependencies: '@sindresorhus/is': 4.6.0 @@ -16347,6 +16669,12 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-forge@1.3.3: {} node-gyp@12.1.0: @@ -16490,6 +16818,8 @@ snapshots: obuf@1.1.2: {} + obug@2.1.1: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -16723,6 +17053,8 @@ snapshots: pify@4.0.1: {} + pkce-challenge@5.0.1: {} + pkg-dir@7.0.0: dependencies: find-up: 6.3.0 @@ -17630,6 +17962,11 @@ snapshots: reusify@1.1.0: {} + rimraf@6.1.2: + dependencies: + glob: 13.0.0 + package-json-from-dist: 1.0.1 + rollup@4.54.0: dependencies: '@types/estree': 1.0.8 @@ -17908,6 +18245,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -18053,6 +18392,8 @@ snapshots: dependencies: minipass: 7.1.2 + stackback@0.0.2: {} + statuses@1.5.0: {} statuses@2.0.2: {} @@ -18321,8 +18662,12 @@ snapshots: tiny-warning@1.0.3: {} + tinybench@2.9.0: {} + tinycolor2@1.6.0: {} + tinyexec@1.0.2: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -18332,6 +18677,8 @@ snapshots: tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} + tinyspy@4.0.4: {} to-regex-range@5.0.1: @@ -18738,6 +19085,44 @@ snapshots: tsx: 4.21.0 yaml: 2.7.0 + vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0): + dependencies: + '@vitest/expect': 4.0.16 + '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0)) + '@vitest/pretty-format': 4.0.16 + '@vitest/runner': 4.0.16 + '@vitest/snapshot': 4.0.16 + '@vitest/spy': 4.0.16 + '@vitest/utils': 4.0.16 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + 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: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.2.2)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 25.0.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + vscode-uri@3.1.0: {} watchpack@2.5.0: @@ -18751,6 +19136,8 @@ snapshots: web-namespaces@2.0.1: {} + web-streams-polyfill@3.3.3: {} + webpack-bundle-analyzer@4.10.2: dependencies: '@discoveryjs/json-ext': 0.5.7 @@ -18972,6 +19359,11 @@ snapshots: dependencies: isexe: 3.1.1 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + widest-line@4.0.1: dependencies: string-width: 5.1.2 @@ -19042,6 +19434,10 @@ snapshots: yocto-queue@1.2.2: {} + zod-to-json-schema@3.25.1(zod@4.2.1): + dependencies: + zod: 4.2.1 + zod-validation-error@4.0.2(zod@4.2.1): dependencies: zod: 4.2.1