diff --git a/alias.ts b/alias.ts index 467c1832e..01c169bf8 100644 --- a/alias.ts +++ b/alias.ts @@ -15,6 +15,7 @@ export const alias = { '@vitejs/devtools-kit/utils/when': r('kit/src/utils/when.ts'), '@vitejs/devtools-kit/utils/shared-state': r('kit/src/utils/shared-state.ts'), '@vitejs/devtools-kit': r('kit/src/index.ts'), + '@vitejs/devtools-rolldown/node/agent': r('rolldown/src/node/agent/index.ts'), '@vitejs/devtools-rolldown': r('rolldown/src/index.ts'), '@vitejs/devtools/internal': r('core/src/internal.ts'), '@vitejs/devtools/client/inject': r('core/src/client/inject/index.ts'), diff --git a/packages/core/package.json b/packages/core/package.json index 0673a8bfc..39ce2510f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -60,6 +60,7 @@ "@devframes/plugin-inspect": "catalog:deps", "@devframes/plugin-messages": "catalog:deps", "@devframes/plugin-terminals": "catalog:deps", + "@modelcontextprotocol/sdk": "catalog:deps", "@vitejs/devtools-kit": "workspace:*", "@vitejs/devtools-rolldown": "workspace:*", "birpc": "catalog:deps", diff --git a/packages/core/src/node/__tests__/context-capabilities.test.ts b/packages/core/src/node/__tests__/context-capabilities.test.ts index 83756d2c7..d4343a9eb 100644 --- a/packages/core/src/node/__tests__/context-capabilities.test.ts +++ b/packages/core/src/node/__tests__/context-capabilities.test.ts @@ -81,4 +81,29 @@ describe('createDevToolsContext capabilities gating', () => { expect(setup).toHaveBeenCalledTimes(1) }) + + it('registers agent tools contributed by configured plugins', async () => { + const plugin: Plugin = { + name: 'test-agent-provider', + devtools: { + setup(ctx) { + ctx.agent.registerTool({ + id: 'test:agent-tool', + title: 'Test agent tool', + description: 'Agent tool contributed by a configured Vite plugin.', + safety: 'read', + inputSchema: { + type: 'object', + additionalProperties: false, + }, + handler: async () => ({ result: 'ok' }), + }) + }, + }, + } + + const context = await createDevToolsContext(createConfig([plugin], 'build')) + + expect(context.agent.getTool('test:agent-tool')).toBeDefined() + }) }) diff --git a/packages/core/src/node/__tests__/standalone.test.ts b/packages/core/src/node/__tests__/standalone.test.ts new file mode 100644 index 000000000..807058ac2 --- /dev/null +++ b/packages/core/src/node/__tests__/standalone.test.ts @@ -0,0 +1,23 @@ +import type { PluginWithDevTools } from '@vitejs/devtools-kit' +import { describe, expect, it, vi } from 'vitest' +import { startStandaloneDevTools } from '../standalone' + +describe('startStandaloneDevTools', () => { + it('includes explicitly provided headless plugins in context setup', async () => { + const setup = vi.fn() + const plugin: PluginWithDevTools = { + name: 'test-headless-agent-provider', + devtools: { + setup, + }, + } + + await startStandaloneDevTools({ + cwd: process.cwd(), + builtinDevTools: false, + plugins: [plugin], + }) + + expect(setup).toHaveBeenCalledOnce() + }) +}) diff --git a/packages/core/src/node/cli-commands.ts b/packages/core/src/node/cli-commands.ts index 07805d16e..d2e7e92ed 100644 --- a/packages/core/src/node/cli-commands.ts +++ b/packages/core/src/node/cli-commands.ts @@ -91,3 +91,12 @@ export async function build(options: BuildOptions) { diagnostics.DTK0010() } + +export interface McpOptions { + root?: string +} + +export async function mcp(options: McpOptions) { + const { startMcpServer } = await import('./mcp') + await startMcpServer(options) +} diff --git a/packages/core/src/node/cli.ts b/packages/core/src/node/cli.ts index c311619cd..5694ec309 100644 --- a/packages/core/src/node/cli.ts +++ b/packages/core/src/node/cli.ts @@ -20,6 +20,14 @@ cli return await build(options) }) +cli + .command('mcp', 'Start Vite DevTools MCP server over stdio') + .option('--root ', 'Root directory', { default: process.cwd() }) + .action(async (options) => { + const { mcp } = await import('./cli-commands') + return await mcp(options) + }) + cli .command('', 'Start devtools') .option('--root ', 'Root directory', { default: process.cwd() }) diff --git a/packages/core/src/node/mcp.ts b/packages/core/src/node/mcp.ts new file mode 100644 index 000000000..91d1c785b --- /dev/null +++ b/packages/core/src/node/mcp.ts @@ -0,0 +1,138 @@ +/* eslint-disable no-console */ + +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import type { AgentResource, AgentTool, DevframeNodeContext } from 'devframe/types' +import process from 'node:process' +import { createMcpServer } from 'devframe/adapters/mcp' +import { defineDevframe } from 'devframe/types' +import packageJson from '../../package.json' with { type: 'json' } + +export interface McpOptions { + root?: string +} + +function redirectConsoleOutputToStderr() { + const originalLog = console.log + const originalInfo = console.info + const originalDebug = console.debug + console.log = (...args: unknown[]) => { + console.error(...args) + } + console.info = (...args: unknown[]) => { + console.error(...args) + } + console.debug = (...args: unknown[]) => { + console.error(...args) + } + return () => { + console.log = originalLog + console.info = originalInfo + console.debug = originalDebug + } +} + +function waitForStdioClose() { + return new Promise((resolve) => { + const done = () => resolve() + process.stdin.once('end', done) + process.stdin.once('close', done) + process.once('SIGINT', done) + process.once('SIGTERM', done) + }) +} + +function registerToolProxy( + target: DevframeNodeContext, + source: ViteDevToolsNodeContext, + tool: AgentTool, +) { + return target.agent.registerTool({ + id: tool.id, + title: tool.title, + description: tool.description, + safety: tool.safety, + tags: tool.tags, + inputSchema: tool.inputSchema, + outputSchema: tool.outputSchema, + examples: tool.examples, + handler: args => source.agent.invoke(tool.id, args ?? {}), + }) +} + +function registerResourceProxy( + target: DevframeNodeContext, + source: ViteDevToolsNodeContext, + resource: AgentResource, +) { + return target.agent.registerResource({ + id: resource.id, + name: resource.name, + description: resource.description, + mimeType: resource.mimeType, + uri: resource.uri, + read: () => source.agent.read(resource.id), + }) +} + +function mirrorAgentSurface(target: DevframeNodeContext, source: ViteDevToolsNodeContext) { + const handles: Array<{ unregister: () => void }> = [] + + const sync = () => { + while (handles.length) { + handles.pop()!.unregister() + } + + const manifest = source.agent.list() + for (const tool of manifest.tools) { + handles.push(registerToolProxy(target, source, tool)) + } + for (const resource of manifest.resources) { + handles.push(registerResourceProxy(target, source, resource)) + } + } + + sync() + source.agent.events.on('agent:manifest:changed', sync) +} + +function createViteDevToolsMcpDefinition(options: McpOptions) { + return defineDevframe({ + id: 'vite-devtools', + name: 'Vite DevTools', + packageName: packageJson.name, + version: packageJson.version, + description: packageJson.description, + homepage: packageJson.homepage, + async setup(ctx) { + const { DevToolsRolldownAgent } = await import('@vitejs/devtools-rolldown/node/agent') + const { startStandaloneDevTools } = await import('./standalone') + + const { context } = await startStandaloneDevTools({ + cwd: options.root, + builtinDevTools: false, + plugins: [ + DevToolsRolldownAgent(), + ], + }) + + mirrorAgentSurface(ctx, context) + }, + }) +} + +export async function startMcpServer(options: McpOptions = {}) { + const restoreConsole = redirectConsoleOutputToStderr() + let handle: Awaited> | undefined + try { + handle = await createMcpServer(createViteDevToolsMcpDefinition(options), { + transport: 'stdio', + serverName: 'vite-devtools', + serverVersion: packageJson.version, + }) + await waitForStdioClose() + } + finally { + await handle?.stop() + restoreConsole() + } +} diff --git a/packages/core/src/node/standalone.ts b/packages/core/src/node/standalone.ts index 37e688952..270c17d60 100644 --- a/packages/core/src/node/standalone.ts +++ b/packages/core/src/node/standalone.ts @@ -1,5 +1,5 @@ import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' -import type { Plugin, ResolvedConfig } from 'vite' +import type { Plugin, PluginOption, ResolvedConfig } from 'vite' import process from 'node:process' import { createDevToolsContext } from './context' import { DevTools } from './plugins' @@ -10,6 +10,8 @@ export interface StandaloneDevToolsOptions { config?: string command?: 'build' | 'serve' mode?: 'development' | 'production' + builtinDevTools?: boolean + plugins?: PluginOption[] } export async function startStandaloneDevTools(options: StandaloneDevToolsOptions = {}): Promise<{ @@ -20,6 +22,8 @@ export async function startStandaloneDevTools(options: StandaloneDevToolsOptions cwd = process.cwd(), command = 'build', mode = 'production', + builtinDevTools = true, + plugins = [], } = options const { resolveConfig } = await import('vite') @@ -28,7 +32,8 @@ export async function startStandaloneDevTools(options: StandaloneDevToolsOptions configFile: options.config, root: cwd, plugins: [ - DevTools(), + ...plugins, + DevTools({ builtinDevTools }), ], }, command, diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 8a6d5a7d1..d03db2f87 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "composite": true, + "composite": false, "lib": ["esnext", "dom"] } } diff --git a/packages/rolldown/package.json b/packages/rolldown/package.json index d4e23c4bf..cf347e5bb 100644 --- a/packages/rolldown/package.json +++ b/packages/rolldown/package.json @@ -20,6 +20,7 @@ "exports": { ".": "./dist/index.mjs", "./dirs": "./dist/dirs.mjs", + "./node/agent": "./dist/node/agent.mjs", "./package.json": "./package.json" }, "types": "./dist/index.d.mts", diff --git a/packages/rolldown/src/node/agent/__tests__/plugin.test.ts b/packages/rolldown/src/node/agent/__tests__/plugin.test.ts new file mode 100644 index 000000000..9aa050314 --- /dev/null +++ b/packages/rolldown/src/node/agent/__tests__/plugin.test.ts @@ -0,0 +1,26 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import { describe, expect, it, vi } from 'vitest' +import { DevToolsRolldownAgent } from '../index' + +describe('devToolsRolldownAgent', () => { + it('registers Rolldown tools through the standard devtools setup hook', async () => { + const registerTool = vi.fn() + const context = { + agent: { + registerTool, + }, + } as unknown as ViteDevToolsNodeContext + + const plugin = DevToolsRolldownAgent() + await plugin.devtools?.setup(context) + + expect(plugin.name).toBe('vite:devtools:rolldown-agent') + expect(registerTool.mock.calls.map(([tool]) => tool.id)).toEqual([ + 'rolldown:build-analysis', + 'rolldown:build-time-analysis', + 'rolldown:bundle-size-analysis', + 'rolldown:dependency-trace', + 'rolldown:build-comparison', + ]) + }) +}) diff --git a/packages/rolldown/src/node/agent/analysis.ts b/packages/rolldown/src/node/agent/analysis.ts new file mode 100644 index 000000000..4335281f6 --- /dev/null +++ b/packages/rolldown/src/node/agent/analysis.ts @@ -0,0 +1,39 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import { createAnalysisContext } from './context' +import { createBuildAnalysis } from './modules/build-analysis' +import { createBuildComparison } from './modules/build-comparison' +import { createBuildTimeAnalysis } from './modules/build-time-analysis' +import { createBundleSizeAnalysis } from './modules/bundle-size-analysis' +import { createDependencyTrace } from './modules/dependency-trace' + +export type { + BuildAnalysisInput, +} from './modules/build-analysis' +export type { + BuildComparisonInput, +} from './modules/build-comparison' +export type { + BuildTimeAnalysisInput, +} from './modules/build-time-analysis' +export type { + BundleSizeAnalysisInput, +} from './modules/bundle-size-analysis' +export type { + DependencyTraceInput, +} from './modules/dependency-trace' +export type { + AnalysisInsight, + AnalysisReport, +} from './types' + +export function createRolldownAnalysis(context: ViteDevToolsNodeContext) { + const analysisContext = createAnalysisContext(context) + + return { + buildAnalysis: createBuildAnalysis(analysisContext), + buildTimeAnalysis: createBuildTimeAnalysis(analysisContext), + bundleSizeAnalysis: createBundleSizeAnalysis(analysisContext), + dependencyTrace: createDependencyTrace(analysisContext), + buildComparison: createBuildComparison(analysisContext), + } +} diff --git a/packages/rolldown/src/node/agent/context.ts b/packages/rolldown/src/node/agent/context.ts new file mode 100644 index 000000000..a52f4b47d --- /dev/null +++ b/packages/rolldown/src/node/agent/context.ts @@ -0,0 +1,60 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import type { BuildInfo, RolldownLogsManager } from '../rolldown/logs-manager' +import type { AnalysisReport } from './types' +import { getLogsManager } from '../rpc/utils' +import { createEmptyReport, createSessionNotFoundReport } from './utils' + +export interface ResolvedSession { + id?: string + info?: BuildInfo + sessions: BuildInfo[] + report?: AnalysisReport +} + +export interface AgentAnalysisContext { + manager: RolldownLogsManager + listSessions: () => Promise + resolveSession: (tool: string, requested?: string) => Promise +} + +export function createAnalysisContext(context: ViteDevToolsNodeContext): AgentAnalysisContext { + const manager = getLogsManager(context) + + async function listSessions() { + const sessions = await manager.list() + return sessions.toSorted((a, b) => b.timestamp - a.timestamp) + } + + async function resolveSession(tool: string, requested?: string): Promise { + const sessions = await listSessions() + const id = !requested || requested === 'latest' + ? sessions[0]?.id + : requested + + if (!id) { + return { + sessions, + report: createEmptyReport(tool, 'No Rolldown sessions were found.', [ + 'Run a build with Rolldown devtools output enabled before using this tool.', + ]), + } + } + + const info = sessions.find(session => session.id === id) + if (!info && requested && requested !== 'latest') { + return { + id, + sessions, + report: createSessionNotFoundReport(tool, id, sessions), + } + } + + return { id, info, sessions } + } + + return { + manager, + listSessions, + resolveSession, + } +} diff --git a/packages/rolldown/src/node/agent/index.ts b/packages/rolldown/src/node/agent/index.ts new file mode 100644 index 000000000..cbf099ceb --- /dev/null +++ b/packages/rolldown/src/node/agent/index.ts @@ -0,0 +1,13 @@ +import type { PluginWithDevTools } from '@vitejs/devtools-kit' +import { registerRolldownAgentTools } from './tools' + +export function DevToolsRolldownAgent(): PluginWithDevTools { + return { + name: 'vite:devtools:rolldown-agent', + devtools: { + setup: registerRolldownAgentTools, + }, + } +} + +export { registerRolldownAgentTools } from './tools' diff --git a/packages/rolldown/src/node/agent/modules/build-analysis.ts b/packages/rolldown/src/node/agent/modules/build-analysis.ts new file mode 100644 index 000000000..c2d2da1f0 --- /dev/null +++ b/packages/rolldown/src/node/agent/modules/build-analysis.ts @@ -0,0 +1,164 @@ +import type { AgentAnalysisContext } from '../context' +import type { AnalysisCategory, AnalysisInsight, AnalysisReport } from '../types' +import { getPackageMeta } from '../../rpc/functions/rolldown-get-packages' +import { + clampLimit, + createSessionReport, + createSessionStats, + getAssetScope, + getChunkSize, + percentage, + sortByNumberDesc, + sumBy, +} from '../utils' + +export interface BuildAnalysisInput { + session?: string + issue?: 'general' | 'slow-build' | 'large-bundle' | 'unexpected-dependency' | 'chunking' | 'dependency-duplication' + limit?: number +} + +function getIssueCategory(issue: BuildAnalysisInput['issue']): AnalysisCategory | undefined { + if (issue === 'slow-build') + return 'build-time' + if (issue === 'large-bundle') + return 'bundle-size' + if (issue === 'unexpected-dependency' || issue === 'dependency-duplication') + return 'dependency' + if (issue === 'chunking') + return 'chunking' +} + +function prioritizeInsights(insights: AnalysisInsight[], issue: BuildAnalysisInput['issue']) { + const category = getIssueCategory(issue) + if (!category) + return insights + + return insights.toSorted((a, b) => { + const aMatch = a.category === category ? 1 : 0 + const bMatch = b.category === category ? 1 : 0 + return bMatch - aMatch + }) +} + +export function createBuildAnalysis(context: AgentAnalysisContext) { + const { manager, resolveSession } = context + + return async function buildAnalysis(input: BuildAnalysisInput = {}): Promise { + const tool = 'rolldown:build-analysis' + const limit = clampLimit(input.limit) + const resolved = await resolveSession(tool, input.session) + if (resolved.report || !resolved.id) + return resolved.report! + + const reader = await manager.loadAssetSession(resolved.id) + const stats = createSessionStats(reader) + const pluginSummaries = Array.from((await reader.readPluginBuildMetricsSummary()).values()) + const measuredPluginDuration = sumBy(pluginSummaries, item => item.total.duration) + const transformDuration = sumBy(pluginSummaries, item => item.transform.duration) + const chunks = Array.from(reader.manager.chunks.values()) + const packageMeta = getPackageMeta(reader) + const packagesBySize = sortByNumberDesc(packageMeta.packages, pkg => pkg.transformedCodeSize) + const largestPackage = packagesBySize[0] + const assetsBySize = sortByNumberDesc(Array.from(reader.manager.assets.values()), asset => asset.size) + const largestAsset = assetsBySize[0] + const chunksBySize = sortByNumberDesc(chunks, chunk => getChunkSize(reader, chunk)) + const largestChunk = chunksBySize[0] + const duplicatedPackages = packageMeta.packages.filter(pkg => pkg.duplicated) + + const insights: AnalysisInsight[] = [] + + if (measuredPluginDuration > 0 && transformDuration / measuredPluginDuration >= 0.5) { + insights.push({ + id: 'build-time:transform-dominates', + category: 'build-time', + severity: 'medium', + title: 'Transform hooks dominate measured plugin time', + explanation: 'Most measured plugin time is spent in transform hooks, so plugin transforms are the first area to inspect for build-time cost.', + evidence: [ + { label: 'Transform hook time', value: transformDuration, unit: 'ms' }, + { label: 'Measured plugin time', value: measuredPluginDuration, unit: 'ms' }, + { label: 'Share', value: percentage(transformDuration, measuredPluginDuration), unit: 'ratio' }, + ], + recommendations: ['Run rolldown:build-time-analysis to inspect top plugins and modules.'], + }) + } + + if (largestPackage && stats.bundleSize > 0 && largestPackage.transformedCodeSize / stats.bundleSize >= 0.2) { + insights.push({ + id: `bundle-size:large-package:${largestPackage.name}`, + category: 'bundle-size', + severity: 'medium', + title: `Package "${largestPackage.name}" is a large bundle contributor`, + explanation: 'A single package accounts for a large share of transformed bundled code.', + evidence: [ + { label: 'Package size', value: largestPackage.transformedCodeSize, unit: 'bytes', source: { type: 'package', id: largestPackage.id } }, + { label: 'Bundle size', value: stats.bundleSize, unit: 'bytes', source: { type: 'session', id: resolved.id } }, + { label: 'Share', value: percentage(largestPackage.transformedCodeSize, stats.bundleSize), unit: 'ratio' }, + ], + recommendations: [`Run rolldown:dependency-trace for package "${largestPackage.name}" to find importer paths.`], + }) + } + + if (largestAsset && stats.bundleSize > 0 && largestAsset.size / stats.bundleSize >= 0.35) { + insights.push({ + id: `asset:large-output:${largestAsset.filename}`, + category: 'asset', + severity: 'low', + title: `Asset "${largestAsset.filename}" is the largest output`, + explanation: 'The largest emitted asset takes a substantial share of total output size.', + evidence: [ + { label: 'Asset size', value: largestAsset.size, unit: 'bytes', source: { type: 'asset', id: largestAsset.filename } }, + { label: 'Scope', value: getAssetScope(largestAsset, new Map(chunks.map(chunk => [chunk.chunk_id, chunk]))) }, + ], + }) + } + + if (largestChunk) { + const chunkSize = getChunkSize(reader, largestChunk) + if (stats.bundleSize > 0 && chunkSize / stats.bundleSize >= 0.35) { + insights.push({ + id: `chunking:large-chunk:${largestChunk.chunk_id}`, + category: 'chunking', + severity: largestChunk.is_initial ? 'medium' : 'low', + title: `Chunk "${largestChunk.name || largestChunk.chunk_id}" is a large output unit`, + explanation: largestChunk.is_initial + ? 'A large initial chunk can increase startup cost because it is needed for initial loading.' + : 'A large async chunk can still affect the route or interaction that loads it.', + evidence: [ + { label: 'Chunk size', value: chunkSize, unit: 'bytes', source: { type: 'chunk', id: String(largestChunk.chunk_id) } }, + { label: 'Modules in chunk', value: largestChunk.modules.length, unit: 'count', source: { type: 'chunk', id: String(largestChunk.chunk_id) } }, + { label: 'Initial chunk', value: !!largestChunk.is_initial }, + ], + }) + } + } + + if (duplicatedPackages.length) { + insights.push({ + id: 'dependency:duplicated-packages', + category: 'dependency', + severity: duplicatedPackages.length > 3 ? 'medium' : 'low', + title: 'Duplicated packages were detected', + explanation: 'Multiple versions or physical copies of the same package family are present in the bundle.', + evidence: [ + { label: 'Duplicated package entries', value: duplicatedPackages.length, unit: 'count' }, + { label: 'Examples', value: duplicatedPackages.slice(0, limit).map(pkg => `${pkg.name}@${pkg.version}`).join(', ') }, + ], + recommendations: ['Run rolldown:bundle-size-analysis to inspect dependency contributors.'], + }) + } + + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: insights.length + ? `The build completed in ${stats.buildDuration}ms with ${insights.length} notable insight(s).` + : `The build completed in ${stats.buildDuration}ms. No major heuristic insights were detected by the first-pass analysis.`, + summary: stats, + insights: prioritizeInsights(insights, input.issue).slice(0, limit), + limitations: [ + 'This is a heuristic first-pass analysis based on Rolldown debug logs.', + 'Tree-shaking effectiveness is inferred from emitted and transformed sizes; unused export removal is not proven by this report.', + ], + }) + } +} diff --git a/packages/rolldown/src/node/agent/modules/build-comparison.ts b/packages/rolldown/src/node/agent/modules/build-comparison.ts new file mode 100644 index 000000000..c385f7db1 --- /dev/null +++ b/packages/rolldown/src/node/agent/modules/build-comparison.ts @@ -0,0 +1,124 @@ +import type { AgentAnalysisContext } from '../context' +import type { AnalysisInsight, AnalysisReport } from '../types' +import { createSessionCompareDetails } from '../../rpc/functions/rolldown-get-session-compare-details' +import { SCHEMA_VERSION } from '../types' +import { clampLimit, createEmptyReport, createSessionStats } from '../utils' + +export interface BuildComparisonInput { + baseSession: string + currentSession: string + limit?: number +} + +export function createBuildComparison(context: AgentAnalysisContext) { + const { manager, listSessions } = context + + return async function buildComparison(input: BuildComparisonInput): Promise { + const tool = 'rolldown:build-comparison' + const limit = clampLimit(input?.limit) + const sessions = await listSessions() + const baseSession = input?.baseSession + const currentSession = input?.currentSession + + if (!baseSession || !currentSession) { + return createEmptyReport(tool, 'Both baseSession and currentSession are required.', [ + sessions.length + ? `Available sessions: ${sessions.map(item => item.id).join(', ')}.` + : 'No Rolldown sessions were found.', + ]) + } + + const baseInfo = sessions.find(session => session.id === baseSession) + const currentInfo = sessions.find(session => session.id === currentSession) + if (!baseInfo || !currentInfo) { + return createEmptyReport(tool, 'One or both requested sessions were not found.', [ + `Missing sessions: ${[ + baseInfo ? undefined : baseSession, + currentInfo ? undefined : currentSession, + ].filter(Boolean).join(', ')}.`, + ]) + } + + const [baseReader, currentReader] = await Promise.all([ + manager.loadAssetSession(baseSession), + manager.loadAssetSession(currentSession), + ]) + const baseStats = createSessionStats(baseReader) + const currentStats = createSessionStats(currentReader) + const compareDetails = await createSessionCompareDetails(baseReader, currentReader) + + const deltas = { + buildDuration: currentStats.buildDuration - baseStats.buildDuration, + bundleSize: currentStats.bundleSize - baseStats.bundleSize, + initialJs: currentStats.initialJs - baseStats.initialJs, + modules: currentStats.modules - baseStats.modules, + chunks: currentStats.chunks - baseStats.chunks, + assets: currentStats.assets - baseStats.assets, + duplicatedPackages: currentStats.duplicatedPackages - baseStats.duplicatedPackages, + } + + const insights: AnalysisInsight[] = [] + if (deltas.buildDuration !== 0) { + insights.push({ + id: 'comparison:build-duration', + category: 'build-time', + severity: deltas.buildDuration > 0 ? 'medium' : 'info', + title: deltas.buildDuration > 0 ? 'Build duration increased' : 'Build duration decreased', + explanation: 'The overall build duration changed between the selected sessions.', + evidence: [ + { label: 'Previous build duration', value: baseStats.buildDuration, unit: 'ms', source: { type: 'session', id: baseSession } }, + { label: 'Current build duration', value: currentStats.buildDuration, unit: 'ms', source: { type: 'session', id: currentSession } }, + { label: 'Delta', value: deltas.buildDuration, unit: 'ms' }, + ], + }) + } + if (deltas.bundleSize !== 0) { + insights.push({ + id: 'comparison:bundle-size', + category: 'bundle-size', + severity: deltas.bundleSize > 0 ? 'medium' : 'info', + title: deltas.bundleSize > 0 ? 'Bundle size increased' : 'Bundle size decreased', + explanation: 'Total emitted asset size changed between the selected sessions.', + evidence: [ + { label: 'Previous bundle size', value: baseStats.bundleSize, unit: 'bytes', source: { type: 'session', id: baseSession } }, + { label: 'Current bundle size', value: currentStats.bundleSize, unit: 'bytes', source: { type: 'session', id: currentSession } }, + { label: 'Delta', value: deltas.bundleSize, unit: 'bytes' }, + ], + }) + } + + const topAssets = compareDetails.assets.slice(0, limit) + const topChunks = compareDetails.chunks.slice(0, limit) + const topPackages = compareDetails.packages.slice(0, limit) + const topPlugins = compareDetails.plugins.slice(0, limit) + + return { + schemaVersion: SCHEMA_VERSION, + tool, + answer: `Compared "${baseSession}" to "${currentSession}". Bundle size delta: ${deltas.bundleSize} bytes. Build duration delta: ${deltas.buildDuration}ms.`, + summary: { + previous: { + session: baseSession, + timestamp: baseInfo.timestamp, + ...baseStats, + }, + current: { + session: currentSession, + timestamp: currentInfo.timestamp, + ...currentStats, + }, + deltas, + topAssets, + topChunks, + topPackages, + topPlugins, + sessionStats: compareDetails.sessionStats, + }, + insights: insights.slice(0, limit), + limitations: [ + 'Asset and chunk matching normalizes hashed filenames where possible, but renamed or heavily restructured outputs may still appear as added and removed items.', + 'Plugin comparison uses recorded hook durations and call counts; non-plugin build work is represented only in total build duration.', + ], + } + } +} diff --git a/packages/rolldown/src/node/agent/modules/build-time-analysis.ts b/packages/rolldown/src/node/agent/modules/build-time-analysis.ts new file mode 100644 index 000000000..ffcb35120 --- /dev/null +++ b/packages/rolldown/src/node/agent/modules/build-time-analysis.ts @@ -0,0 +1,144 @@ +import type { ModuleBuildMetrics } from '../../../shared/types' +import type { AgentAnalysisContext } from '../context' +import type { AnalysisInsight, AnalysisReport, AssetSessionReader } from '../types' +import { + clampLimit, + createSessionReport, + createSessionStats, + percentage, + sortByNumberDesc, + sumBy, +} from '../utils' + +export interface BuildTimeAnalysisInput { + session?: string + limit?: number +} + +interface ModuleCost { + id: string + totalDuration: number + resolveDuration: number + loadDuration: number + transformDuration: number +} + +function getModuleCost(id: string, metrics: ModuleBuildMetrics | undefined): ModuleCost { + const resolveDuration = sumBy(metrics?.resolve_ids ?? [], item => item.duration) + const loadDuration = sumBy(metrics?.loads ?? [], item => item.duration) + const transformDuration = sumBy(metrics?.transforms ?? [], item => item.duration) + + return { + id, + totalDuration: resolveDuration + loadDuration + transformDuration, + resolveDuration, + loadDuration, + transformDuration, + } +} + +function getTopModuleCosts(reader: AssetSessionReader, limit: number) { + return sortByNumberDesc( + Array.from(reader.manager.modules.entries()) + .map(([id, module]) => getModuleCost(id, module.build_metrics)), + item => item.totalDuration, + ).slice(0, limit) +} + +export function createBuildTimeAnalysis(context: AgentAnalysisContext) { + const { manager, resolveSession } = context + + return async function buildTimeAnalysis(input: BuildTimeAnalysisInput = {}): Promise { + const tool = 'rolldown:build-time-analysis' + const limit = clampLimit(input.limit) + const resolved = await resolveSession(tool, input.session) + if (resolved.report || !resolved.id) + return resolved.report! + + const reader = await manager.loadAssetSession(resolved.id) + const stats = createSessionStats(reader) + const pluginSummaries = Array.from((await reader.readPluginBuildMetricsSummary()).values()) + const hookBreakdown = { + resolve: { + duration: sumBy(pluginSummaries, item => item.resolve.duration), + calls: sumBy(pluginSummaries, item => item.resolve.count), + }, + load: { + duration: sumBy(pluginSummaries, item => item.load.duration), + calls: sumBy(pluginSummaries, item => item.load.count), + }, + transform: { + duration: sumBy(pluginSummaries, item => item.transform.duration), + calls: sumBy(pluginSummaries, item => item.transform.count), + }, + } + const measuredPluginDuration = hookBreakdown.resolve.duration + hookBreakdown.load.duration + hookBreakdown.transform.duration + const topPlugins = sortByNumberDesc(pluginSummaries, item => item.total.duration) + .slice(0, limit) + .map(plugin => ({ + pluginId: plugin.plugin_id, + name: plugin.plugin_name, + totalDuration: plugin.total.duration, + totalCalls: plugin.total.count, + resolveDuration: plugin.resolve.duration, + resolveCalls: plugin.resolve.count, + loadDuration: plugin.load.duration, + loadCalls: plugin.load.count, + transformDuration: plugin.transform.duration, + transformCalls: plugin.transform.count, + })) + const topModules = getTopModuleCosts(reader, limit) + + const insights: AnalysisInsight[] = [] + const topPlugin = topPlugins[0] + if (topPlugin && measuredPluginDuration > 0) { + insights.push({ + id: `plugin:top-cost:${topPlugin.pluginId}`, + category: 'plugin', + severity: percentage(topPlugin.totalDuration, measuredPluginDuration) >= 0.35 ? 'medium' : 'low', + title: `Plugin "${topPlugin.name}" has the highest measured hook cost`, + explanation: 'This plugin accounts for the largest share of measured plugin hook duration.', + evidence: [ + { label: 'Plugin duration', value: topPlugin.totalDuration, unit: 'ms', source: { type: 'plugin', id: String(topPlugin.pluginId) } }, + { label: 'Plugin calls', value: topPlugin.totalCalls, unit: 'count', source: { type: 'plugin', id: String(topPlugin.pluginId) } }, + { label: 'Share of measured plugin time', value: percentage(topPlugin.totalDuration, measuredPluginDuration), unit: 'ratio' }, + ], + }) + } + + const topModule = topModules[0] + if (topModule && topModule.totalDuration > 0) { + insights.push({ + id: `module:top-build-cost:${topModule.id}`, + category: 'module', + severity: 'low', + title: `Module "${topModule.id}" has the highest measured build cost`, + explanation: 'This module has the largest combined resolve, load, and transform duration in the current build data.', + evidence: [ + { label: 'Module duration', value: topModule.totalDuration, unit: 'ms', source: { type: 'module', id: topModule.id } }, + { label: 'Resolve duration', value: topModule.resolveDuration, unit: 'ms' }, + { label: 'Load duration', value: topModule.loadDuration, unit: 'ms' }, + { label: 'Transform duration', value: topModule.transformDuration, unit: 'ms' }, + ], + }) + } + + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: measuredPluginDuration > 0 + ? `Measured plugin hooks took ${measuredPluginDuration}ms. The top plugin is "${topPlugins[0]?.name ?? 'unknown'}".` + : 'No measured plugin hook duration was found in this session.', + summary: { + buildDuration: stats.buildDuration, + measuredPluginDuration, + hookBreakdown, + topPlugins, + topModules, + }, + insights, + limitations: [ + 'Build duration and measured plugin hook duration are related but not identical; Rolldown work outside plugin hooks is not attributed to a plugin.', + 'Module cost is based on recorded resolve, load, and transform hook metrics.', + ], + }) + } +} diff --git a/packages/rolldown/src/node/agent/modules/bundle-size-analysis.ts b/packages/rolldown/src/node/agent/modules/bundle-size-analysis.ts new file mode 100644 index 000000000..f715d5b8d --- /dev/null +++ b/packages/rolldown/src/node/agent/modules/bundle-size-analysis.ts @@ -0,0 +1,139 @@ +import type { AgentAnalysisContext } from '../context' +import type { AnalysisInsight, AnalysisReport } from '../types' +import { getPackageMeta } from '../../rpc/functions/rolldown-get-packages' +import { + clampLimit, + createSessionReport, + createSessionStats, + getAssetScope, + getChunkSize, + percentage, + sortByNumberDesc, + sumBy, +} from '../utils' + +export interface BundleSizeAnalysisInput { + session?: string + scope?: 'all' | 'initial' | 'async' | 'assets' + limit?: number +} + +export function createBundleSizeAnalysis(context: AgentAnalysisContext) { + const { manager, resolveSession } = context + + return async function bundleSizeAnalysis(input: BundleSizeAnalysisInput = {}): Promise { + const tool = 'rolldown:bundle-size-analysis' + const limit = clampLimit(input.limit) + const scope = input.scope ?? 'all' + const resolved = await resolveSession(tool, input.session) + if (resolved.report || !resolved.id) + return resolved.report! + + const reader = await manager.loadAssetSession(resolved.id) + const stats = createSessionStats(reader) + const chunks = Array.from(reader.manager.chunks.values()) + const chunkMap = new Map(chunks.map(chunk => [chunk.chunk_id, chunk])) + const packageMeta = getPackageMeta(reader) + const analyzedAssets = Array.from(reader.manager.assets.values()) + .filter((asset) => { + if (scope === 'assets') + return asset.chunk_id == null + if (scope === 'initial') + return asset.chunk_id != null && chunkMap.get(asset.chunk_id)?.is_initial + if (scope === 'async') + return asset.chunk_id != null && !chunkMap.get(asset.chunk_id)?.is_initial + return true + }) + const analyzedAssetSize = sumBy(analyzedAssets, asset => asset.size) + const largestAssets = sortByNumberDesc(analyzedAssets, asset => asset.size) + .slice(0, limit) + .map(asset => ({ + filename: asset.filename, + size: asset.size, + scope: getAssetScope(asset, chunkMap), + chunkId: asset.chunk_id, + share: percentage(asset.size, analyzedAssetSize), + })) + const largestChunks = sortByNumberDesc(chunks, chunk => getChunkSize(reader, chunk)) + .slice(0, limit) + .map(chunk => ({ + chunkId: chunk.chunk_id, + name: chunk.name, + reason: chunk.reason, + initial: !!chunk.is_initial, + modules: chunk.modules.length, + size: getChunkSize(reader, chunk), + })) + const largestPackages = sortByNumberDesc(packageMeta.packages, pkg => pkg.transformedCodeSize) + .slice(0, limit) + .map(pkg => ({ + id: pkg.id, + name: pkg.name, + version: pkg.version, + type: pkg.type, + size: pkg.transformedCodeSize, + files: pkg.files.length, + duplicated: !!pkg.duplicated, + share: percentage(pkg.transformedCodeSize, stats.bundleSize), + })) + const duplicatedPackages = packageMeta.packages + .filter(pkg => pkg.duplicated) + .map(pkg => ({ + id: pkg.id, + name: pkg.name, + version: pkg.version, + size: pkg.transformedCodeSize, + })) + .slice(0, limit) + + const insights: AnalysisInsight[] = [] + const largestPackage = largestPackages[0] + if (largestPackage) { + insights.push({ + id: `bundle-size:top-package:${largestPackage.id}`, + category: 'dependency', + severity: largestPackage.share >= 0.2 ? 'medium' : 'low', + title: `Package "${largestPackage.name}" is the largest package contributor`, + explanation: 'This package contributes the largest transformed code size among package graph entries.', + evidence: [ + { label: 'Package size', value: largestPackage.size, unit: 'bytes', source: { type: 'package', id: largestPackage.id } }, + { label: 'Share of total emitted assets', value: largestPackage.share, unit: 'ratio' }, + { label: 'Bundled files', value: largestPackage.files, unit: 'count' }, + ], + }) + } + if (duplicatedPackages.length) { + insights.push({ + id: 'bundle-size:duplicated-packages', + category: 'dependency', + severity: duplicatedPackages.length > 3 ? 'medium' : 'low', + title: 'Duplicated package entries increase bundle complexity', + explanation: 'Duplicated package entries can indicate multiple versions or duplicated physical package copies in the bundled dependency graph.', + evidence: [ + { label: 'Duplicated package entries', value: duplicatedPackages.length, unit: 'count' }, + { label: 'Examples', value: duplicatedPackages.map(pkg => `${pkg.name}@${pkg.version}`).join(', ') }, + ], + }) + } + + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: `The selected scope contains ${analyzedAssetSize} bytes across ${analyzedAssets.length} asset(s).`, + summary: { + scope, + totalAssetSize: analyzedAssetSize, + bundleSize: stats.bundleSize, + initialJs: stats.initialJs, + topAssets: largestAssets, + topChunks: largestChunks, + packageGraphSupported: packageMeta.isSupported, + topPackages: largestPackages, + duplicatedPackages, + }, + insights, + limitations: [ + 'Package sizes are based on transformed module sizes attributed to package graph entries.', + 'Chunk sizes prefer emitted asset size and fall back to summed transformed module size when an emitted asset is unavailable.', + ], + }) + } +} diff --git a/packages/rolldown/src/node/agent/modules/dependency-trace.ts b/packages/rolldown/src/node/agent/modules/dependency-trace.ts new file mode 100644 index 000000000..dbdda31b9 --- /dev/null +++ b/packages/rolldown/src/node/agent/modules/dependency-trace.ts @@ -0,0 +1,215 @@ +import type { PackageInfo, RolldownAssetInfo } from '../../../shared/types' +import type { AgentAnalysisContext } from '../context' +import type { AnalysisReport } from '../types' +import { getPackageMeta } from '../../rpc/functions/rolldown-get-packages' +import { clampDepth, clampLimit, createSessionReport, getChunkSize } from '../utils' + +export interface DependencyTraceInput { + session?: string + target: { + type: 'module' | 'package' | 'asset' + id: string + } + direction?: 'importers' | 'imports' | 'both' + maxDepth?: number + limit?: number +} + +type ModuleGraph = Map + importers?: string[] +}> + +function isTargetPackage(pkg: PackageInfo, target: string) { + return pkg.id === target + || pkg.name === target + || `${pkg.name}@${pkg.version}` === target + || pkg.dir === target +} + +function getGraphPaths( + targets: string[], + maxDepth: number, + limit: number, + getNext: (id: string) => string[], + options: { reverse?: boolean } = {}, +) { + const paths: string[][] = [] + const queue = targets.map(id => ({ id, path: [id] })) + + while (queue.length && paths.length < limit) { + const current = queue.shift()! + const nextIds = getNext(current.id) + + if (!nextIds.length || current.path.length >= maxDepth) { + paths.push(options.reverse ? current.path.toReversed() : current.path) + continue + } + + for (const nextId of nextIds) { + if (paths.length + queue.length >= limit) + break + if (current.path.includes(nextId)) + continue + queue.push({ + id: nextId, + path: [...current.path, nextId], + }) + } + } + + return paths +} + +function getImporterPaths( + modules: ModuleGraph, + targets: string[], + maxDepth: number, + limit: number, +) { + return getGraphPaths( + targets, + maxDepth, + limit, + id => modules.get(id)?.importers?.filter(importer => modules.has(importer)) ?? [], + { reverse: true }, + ) +} + +function getImportPaths( + modules: ModuleGraph, + targets: string[], + maxDepth: number, + limit: number, +) { + return getGraphPaths( + targets, + maxDepth, + limit, + id => modules.get(id)?.imports?.map(item => item.module_id).filter(imported => modules.has(imported)) ?? [], + ) +} + +function formatTraceAnswer( + target: DependencyTraceInput['target'], + targetLabel: string, + importerPaths: string[][], + importPaths: string[][], +) { + if (importerPaths[0]) + return `${target.type} "${targetLabel}" is included through ${importerPaths[0].join(' -> ')}.` + if (importPaths[0]) + return `${target.type} "${targetLabel}" has an import path: ${importPaths[0].join(' -> ')}.` + return `${target.type} "${targetLabel}" was found in the bundle, but no graph path was resolved within the requested depth.` +} + +export function createDependencyTrace(context: AgentAnalysisContext) { + const { manager, resolveSession } = context + + return async function dependencyTrace(input: DependencyTraceInput): Promise { + const tool = 'rolldown:dependency-trace' + const limit = clampLimit(input?.limit) + const maxDepth = clampDepth(input?.maxDepth) + const direction = input?.direction ?? 'importers' + const resolved = await resolveSession(tool, input?.session) + if (resolved.report || !resolved.id) + return resolved.report! + + const reader = await manager.loadAssetSession(resolved.id) + const packageMeta = getPackageMeta(reader) + const modules = reader.manager.modules as ModuleGraph + const chunks = Array.from(reader.manager.chunks.values()) + const chunkMap = new Map(chunks.map(chunk => [chunk.chunk_id, chunk])) + const target = input?.target + + if (!target) { + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: 'No trace target was provided.', + limitations: ['Provide target.type and target.id to trace module, package, or asset inclusion.'], + }) + } + + let matchedModuleIds: string[] = [] + let targetLabel = target.id + let matchedPackages: PackageInfo[] = [] + let matchedAsset: RolldownAssetInfo | undefined + + if (target.type === 'module') { + matchedModuleIds = modules.has(target.id) + ? [target.id] + : Array.from(modules.keys()).filter(id => id.includes(target.id)).slice(0, limit) + } + else if (target.type === 'package') { + matchedPackages = packageMeta.packages.filter(pkg => isTargetPackage(pkg, target.id)) + matchedModuleIds = Array.from(new Set(matchedPackages.flatMap(pkg => pkg.files.map(file => file.path)))) + targetLabel = matchedPackages[0]?.name ?? target.id + } + else if (target.type === 'asset') { + matchedAsset = reader.manager.assets.get(target.id) + ?? Array.from(reader.manager.assets.values()).find(asset => asset.filename.includes(target.id)) + const chunk = matchedAsset?.chunk_id == null ? undefined : chunkMap.get(matchedAsset.chunk_id) + matchedModuleIds = chunk?.entry_module + ? [chunk.entry_module] + : chunk?.modules.slice(0, limit) ?? [] + targetLabel = matchedAsset?.filename ?? target.id + } + + matchedModuleIds = matchedModuleIds.filter(module => modules.has(module)).slice(0, limit) + + if (!matchedModuleIds.length) { + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: `No bundled module was found for ${target.type} "${target.id}".`, + summary: { + target, + packageGraphSupported: packageMeta.isSupported, + }, + limitations: [ + target.type === 'package' + ? 'Package tracing requires Rolldown package graph data.' + : 'The target may be external, removed by bundling, or represented by a different module id.', + ], + }) + } + + const importerPaths = direction === 'imports' + ? [] + : getImporterPaths(modules, matchedModuleIds, maxDepth, limit) + const importPaths = direction === 'importers' + ? [] + : getImportPaths(modules, matchedModuleIds, maxDepth, limit) + const matchedModuleIdSet = new Set(matchedModuleIds) + const relatedChunks = chunks + .filter(chunk => chunk.modules.some(module => matchedModuleIdSet.has(module))) + .map(chunk => ({ + chunkId: chunk.chunk_id, + name: chunk.name, + initial: !!chunk.is_initial, + size: getChunkSize(reader, chunk), + modules: chunk.modules.length, + })) + .slice(0, limit) + + return createSessionReport(tool, resolved.id, resolved.sessions, { + answer: formatTraceAnswer(target, targetLabel, importerPaths, importPaths), + summary: { + target, + matchedModules: matchedModuleIds, + matchedPackages: matchedPackages.map(pkg => ({ id: pkg.id, name: pkg.name, version: pkg.version, files: pkg.files.length })), + matchedAsset: matchedAsset + ? { + filename: matchedAsset.filename, + size: matchedAsset.size, + chunkId: matchedAsset.chunk_id, + } + : undefined, + importerPaths, + importPaths, + relatedChunks, + }, + limitations: [ + 'Graph paths are derived from the recorded module graph and are capped by maxDepth and limit.', + 'A path ending before an entry module can indicate a graph root, an external boundary, or the configured depth limit.', + ], + }) + } +} diff --git a/packages/rolldown/src/node/agent/tools.ts b/packages/rolldown/src/node/agent/tools.ts new file mode 100644 index 000000000..b0220ff1b --- /dev/null +++ b/packages/rolldown/src/node/agent/tools.ts @@ -0,0 +1,202 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import type { + BuildAnalysisInput, + BuildComparisonInput, + BuildTimeAnalysisInput, + BundleSizeAnalysisInput, + DependencyTraceInput, +} from './analysis' +import { createRolldownAnalysis } from './analysis' + +const sessionProperty = { + type: 'string', + description: 'Rolldown session id to analyze. Use "latest" or omit this field to analyze the newest session.', +} as const + +const limitProperty = { + type: 'number', + description: 'Maximum number of ranked insights, items, or paths to return. Defaults to 5 and is capped at 200.', + minimum: 1, + maximum: 200, +} as const + +const readOnlyTags = ['rolldown', 'build-analysis'] as const + +const outputSchema = { + type: 'object', + additionalProperties: true, +} as const + +export function registerRolldownAgentTools(ctx: ViteDevToolsNodeContext) { + let analysis: ReturnType | undefined + const getAnalysis = () => { + analysis ??= createRolldownAnalysis(ctx) + return analysis + } + + ctx.agent.registerTool({ + id: 'rolldown:build-analysis', + title: 'Rolldown build analysis', + description: 'Analyze a Rolldown build and explain the most important findings across build time, bundle size, chunks, assets, and dependencies. Use this as the default tool for general build questions or when the cause of a build issue is unclear.', + safety: 'read', + tags: readOnlyTags, + inputSchema: { + type: 'object', + properties: { + session: sessionProperty, + issue: { + type: 'string', + description: 'Optional issue hint that helps prioritize insights.', + enum: ['general', 'slow-build', 'large-bundle', 'unexpected-dependency', 'chunking', 'dependency-duplication'], + }, + limit: limitProperty, + }, + additionalProperties: false, + }, + outputSchema, + examples: [ + { + args: [{ session: 'latest', issue: 'general', limit: 5 }], + description: 'Explain the latest build and return the top insights.', + }, + ], + handler: args => getAnalysis().buildAnalysis(args as BuildAnalysisInput), + }) + + ctx.agent.registerTool({ + id: 'rolldown:build-time-analysis', + title: 'Rolldown build time analysis', + description: 'Show where a Rolldown build spends its time, with breakdowns by hook, plugin, and module. Use this to identify likely build-time bottlenecks.', + safety: 'read', + tags: [...readOnlyTags, 'performance'], + inputSchema: { + type: 'object', + properties: { + session: sessionProperty, + limit: limitProperty, + }, + additionalProperties: false, + }, + outputSchema, + examples: [ + { + args: [{ session: 'latest', limit: 5 }], + description: 'Find the highest-cost plugins and hooks in the latest build.', + }, + ], + handler: args => getAnalysis().buildTimeAnalysis(args as BuildTimeAnalysisInput), + }) + + ctx.agent.registerTool({ + id: 'rolldown:bundle-size-analysis', + title: 'Rolldown bundle size analysis', + description: 'Explain what contributes to a Rolldown build\'s output size, including initial JavaScript, large chunks, assets, packages, and duplicated dependencies. Use this to investigate unexpectedly large output or identify the biggest contributors.', + safety: 'read', + tags: [...readOnlyTags, 'bundle-size'], + inputSchema: { + type: 'object', + properties: { + session: sessionProperty, + scope: { + type: 'string', + description: 'Output scope to focus on.', + enum: ['all', 'initial', 'async', 'assets'], + }, + limit: limitProperty, + }, + additionalProperties: false, + }, + outputSchema, + examples: [ + { + args: [{ session: 'latest', scope: 'initial', limit: 5 }], + description: 'Analyze the largest contributors to initial output size.', + }, + ], + handler: args => getAnalysis().bundleSizeAnalysis(args as BundleSizeAnalysisInput), + }) + + ctx.agent.registerTool({ + id: 'rolldown:dependency-trace', + title: 'Rolldown dependency trace', + description: 'Trace why a module, package, or asset appears in a Rolldown build. Follow its importer paths and related chunks to explain what brought it into the output.', + safety: 'read', + tags: [...readOnlyTags, 'trace'], + inputSchema: { + type: 'object', + required: ['target'], + properties: { + session: sessionProperty, + target: { + type: 'object', + required: ['type', 'id'], + additionalProperties: false, + properties: { + type: { + type: 'string', + description: 'Kind of build entity to trace.', + enum: ['module', 'package', 'asset'], + }, + id: { + type: 'string', + description: 'Module id, package name/id, or asset filename to trace.', + }, + }, + }, + direction: { + type: 'string', + description: 'Trace importers, imports, or both directions. Importers answer why something is included.', + enum: ['importers', 'imports', 'both'], + }, + maxDepth: { + type: 'number', + description: 'Maximum graph depth to traverse. Defaults to 8 and is capped at 100.', + minimum: 1, + maximum: 100, + }, + limit: limitProperty, + }, + additionalProperties: false, + }, + outputSchema, + examples: [ + { + args: [{ session: 'latest', target: { type: 'package', id: 'lodash' }, direction: 'importers', maxDepth: 8, limit: 5 }], + description: 'Explain why a package is included in the latest build.', + }, + ], + handler: args => getAnalysis().dependencyTrace(args as DependencyTraceInput), + }) + + ctx.agent.registerTool({ + id: 'rolldown:build-comparison', + title: 'Rolldown build comparison', + description: 'Compare two Rolldown builds and explain meaningful changes in build time, output size, assets, chunks, packages, and plugin cost. Use this to investigate regressions or unexpected differences between builds.', + safety: 'read', + tags: [...readOnlyTags, 'comparison'], + inputSchema: { + type: 'object', + required: ['baseSession', 'currentSession'], + properties: { + baseSession: { + type: 'string', + description: 'Older or baseline Rolldown session id.', + }, + currentSession: { + type: 'string', + description: 'Newer or candidate Rolldown session id.', + }, + limit: limitProperty, + }, + additionalProperties: false, + }, + outputSchema, + examples: [ + { + args: [{ baseSession: 'previous-session-id', currentSession: 'current-session-id', limit: 5 }], + description: 'Compare two builds and return the most relevant changes.', + }, + ], + handler: args => getAnalysis().buildComparison(args as BuildComparisonInput), + }) +} diff --git a/packages/rolldown/src/node/agent/types.ts b/packages/rolldown/src/node/agent/types.ts new file mode 100644 index 000000000..8fe5ec3a3 --- /dev/null +++ b/packages/rolldown/src/node/agent/types.ts @@ -0,0 +1,58 @@ +import type { RolldownLogsManager } from '../rolldown/logs-manager' + +export const SCHEMA_VERSION = 'rolldown-agent' + +export type AnalysisSeverity = 'info' | 'low' | 'medium' | 'high' +export type AnalysisCategory = 'build-time' | 'bundle-size' | 'dependency' | 'chunking' | 'plugin' | 'asset' | 'module' +export type AnalysisUnit = 'ms' | 'bytes' | 'count' | 'percent' | 'ratio' +export type AssetSessionReader = Awaited> + +export interface EvidenceSource { + type: 'session' | 'module' | 'package' | 'plugin' | 'chunk' | 'asset' + id: string +} + +export interface EvidenceItem { + label: string + value: string | number | boolean | null + unit?: AnalysisUnit + source?: EvidenceSource +} + +export interface AnalysisInsight { + id: string + category: AnalysisCategory + severity: AnalysisSeverity + title: string + explanation: string + evidence: EvidenceItem[] + recommendations?: string[] +} + +export interface AnalysisSession { + id: string + timestamp?: number +} + +export interface AnalysisReport { + schemaVersion: typeof SCHEMA_VERSION + tool: string + session?: AnalysisSession + answer: string + summary?: object + insights?: AnalysisInsight[] + limitations?: string[] +} + +export interface SessionStats { + buildDuration: number + modules: number + chunks: number + assets: number + plugins: number + bundleSize: number + initialJs: number + packageGraphSupported: boolean + packages: number + duplicatedPackages: number +} diff --git a/packages/rolldown/src/node/agent/utils.ts b/packages/rolldown/src/node/agent/utils.ts new file mode 100644 index 000000000..775a77d98 --- /dev/null +++ b/packages/rolldown/src/node/agent/utils.ts @@ -0,0 +1,123 @@ +import type { RolldownAssetInfo, RolldownChunkInfo } from '../../shared/types' +import type { BuildInfo } from '../rolldown/logs-manager' +import type { AnalysisReport, AssetSessionReader, SessionStats } from './types' +import { getPackageMeta } from '../rpc/functions/rolldown-get-packages' +import { SCHEMA_VERSION } from './types' + +const DEFAULT_LIMIT = 5 +const MAX_LIMIT = 200 +const DEFAULT_TRACE_DEPTH = 8 +const MAX_TRACE_DEPTH = 100 + +export function clampLimit(limit: unknown, fallback = DEFAULT_LIMIT) { + if (typeof limit !== 'number' || !Number.isFinite(limit)) + return fallback + return Math.min(MAX_LIMIT, Math.max(1, Math.floor(limit))) +} + +export function clampDepth(depth: unknown) { + if (typeof depth !== 'number' || !Number.isFinite(depth)) + return DEFAULT_TRACE_DEPTH + return Math.min(MAX_TRACE_DEPTH, Math.max(1, Math.floor(depth))) +} + +export function sortByNumberDesc(items: T[], getValue: (item: T) => number) { + return items.toSorted((a, b) => getValue(b) - getValue(a)) +} + +export function sumBy(items: Iterable, getValue: (item: T) => number) { + let total = 0 + for (const item of items) { + total += getValue(item) + } + return total +} + +export function percentage(value: number, total: number) { + return total > 0 ? value / total : 0 +} + +export function getSessionTimestamp(sessions: BuildInfo[], id: string) { + return sessions.find(session => session.id === id)?.timestamp +} + +export function createEmptyReport(tool: string, answer: string, limitations: string[] = []): AnalysisReport { + return { + schemaVersion: SCHEMA_VERSION, + tool, + answer, + limitations, + } +} + +export function createSessionReport( + tool: string, + session: string, + sessions: BuildInfo[], + data: Omit, +): AnalysisReport { + return { + schemaVersion: SCHEMA_VERSION, + tool, + session: { + id: session, + timestamp: getSessionTimestamp(sessions, session), + }, + ...data, + } +} + +export function createSessionNotFoundReport(tool: string, session: string, sessions: BuildInfo[]): AnalysisReport { + return createEmptyReport( + tool, + `Rolldown session "${session}" was not found.`, + [ + sessions.length + ? `Available sessions: ${sessions.map(item => item.id).join(', ')}.` + : 'No Rolldown sessions were found. Run a build with Rolldown devtools output enabled first.', + ], + ) +} + +export function getBuildDuration(reader: AssetSessionReader) { + return Math.max(0, reader.manager.build_end_time - reader.manager.build_start_time) +} + +export function getAssetScope(asset: RolldownAssetInfo, chunks: Map) { + if (asset.chunk_id == null) + return 'static' + return chunks.get(asset.chunk_id)?.is_initial ? 'initial' : 'async' +} + +export function getModuleTransformedSize(reader: AssetSessionReader, id: string) { + const transforms = reader.manager.modules.get(id)?.build_metrics?.transforms + return transforms?.at(-1)?.transformed_code_size ?? 0 +} + +export function getChunkSize(reader: AssetSessionReader, chunk: RolldownChunkInfo) { + const asset = reader.manager.chunkAssetMap.get(chunk.chunk_id) + if (asset) + return asset.size + + return chunk.modules.reduce((total, id) => total + getModuleTransformedSize(reader, id), 0) +} + +export function createSessionStats(reader: AssetSessionReader): SessionStats { + const assets = Array.from(reader.manager.assets.values()) + const chunks = Array.from(reader.manager.chunks.values()) + const initialChunkIds = new Set(chunks.filter(chunk => chunk.is_initial).map(chunk => chunk.chunk_id)) + const packageMeta = getPackageMeta(reader) + + return { + buildDuration: getBuildDuration(reader), + modules: reader.manager.modules.size, + chunks: chunks.length, + assets: assets.length, + plugins: reader.meta?.plugins?.length ?? 0, + bundleSize: sumBy(assets, asset => asset.size), + initialJs: sumBy(assets.filter(asset => asset.chunk_id != null && initialChunkIds.has(asset.chunk_id)), asset => asset.size), + packageGraphSupported: packageMeta.isSupported, + packages: packageMeta.packages.length, + duplicatedPackages: packageMeta.packages.filter(pkg => pkg.duplicated).length, + } +} diff --git a/packages/rolldown/src/node/rpc/__tests__/utils.test.ts b/packages/rolldown/src/node/rpc/__tests__/utils.test.ts new file mode 100644 index 000000000..85799d2e7 --- /dev/null +++ b/packages/rolldown/src/node/rpc/__tests__/utils.test.ts @@ -0,0 +1,41 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import { mkdirSync, mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import process from 'node:process' +import { join } from 'pathe' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { diagnostics } from '../../diagnostics' +import { getLogsManager } from '../utils' + +vi.mock('../../diagnostics', () => ({ + diagnostics: { + RDDT0001: vi.fn(), + }, +})) + +describe('getLogsManager', () => { + const tempDirs: string[] = [] + + afterEach(() => { + vi.restoreAllMocks() + for (const dir of tempDirs.splice(0)) + rmSync(dir, { recursive: true, force: true }) + }) + + it('does not fall back to logs from the process working directory', () => { + const tempDir = mkdtempSync(join(tmpdir(), 'vite-devtools-rolldown-root-')) + tempDirs.push(tempDir) + + const targetRoot = join(tempDir, 'target') + const processRoot = join(tempDir, 'launcher') + mkdirSync(targetRoot, { recursive: true }) + mkdirSync(join(processRoot, 'node_modules', '.rolldown'), { recursive: true }) + vi.spyOn(process, 'cwd').mockReturnValue(processRoot) + + const context = { cwd: targetRoot } as ViteDevToolsNodeContext + const manager = getLogsManager(context) + + expect(manager.dir).toBe(join(targetRoot, 'node_modules', '.rolldown')) + expect(diagnostics.RDDT0001).toHaveBeenCalledOnce() + }) +}) diff --git a/packages/rolldown/src/node/rpc/functions/rolldown-get-session-compare-details.ts b/packages/rolldown/src/node/rpc/functions/rolldown-get-session-compare-details.ts index 51820a8ee..7d3dbcb6b 100644 --- a/packages/rolldown/src/node/rpc/functions/rolldown-get-session-compare-details.ts +++ b/packages/rolldown/src/node/rpc/functions/rolldown-get-session-compare-details.ts @@ -397,6 +397,36 @@ async function comparePlugins(previous: SessionCompareSource, current: SessionCo })) } +export async function createSessionCompareDetails( + previousReader: RolldownEventsReader, + currentReader: RolldownEventsReader, +): Promise { + const previous = createCompareSource(previousReader) + const current = createCompareSource(currentReader) + + const assets = compareAssets(previous, current) + const chunks = compareChunks(previous, current) + const packages = comparePackages(previous, current) + const plugins = await comparePlugins(previous, current) + + return { + sessionStats: { + previous: { + packages: previous.packages.length, + duplicatedPackages: previous.packages.filter(pkg => pkg.duplicated).length, + }, + current: { + packages: current.packages.length, + duplicatedPackages: current.packages.filter(pkg => pkg.duplicated).length, + }, + }, + assets, + chunks, + packages, + plugins, + } +} + export const rolldownGetSessionCompareDetails = defineRpcFunction({ name: 'vite:rolldown:get-session-compare-details', type: 'query', @@ -410,30 +440,7 @@ export const rolldownGetSessionCompareDetails = defineRpcFunction({ manager.loadAssetSession(previousSession!), manager.loadAssetSession(currentSession!), ]) - const previous = createCompareSource(previousReader) - const current = createCompareSource(currentReader) - - const assets = compareAssets(previous, current) - const chunks = compareChunks(previous, current) - const packages = comparePackages(previous, current) - const plugins = await comparePlugins(previous, current) - - return { - sessionStats: { - previous: { - packages: previous.packages.length, - duplicatedPackages: previous.packages.filter(pkg => pkg.duplicated).length, - }, - current: { - packages: current.packages.length, - duplicatedPackages: current.packages.filter(pkg => pkg.duplicated).length, - }, - }, - assets, - chunks, - packages, - plugins, - } + return createSessionCompareDetails(previousReader, currentReader) }, } }, diff --git a/packages/rolldown/src/node/rpc/utils.ts b/packages/rolldown/src/node/rpc/utils.ts index cc94f8b26..2abad3fe2 100644 --- a/packages/rolldown/src/node/rpc/utils.ts +++ b/packages/rolldown/src/node/rpc/utils.ts @@ -1,6 +1,5 @@ import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' import { existsSync } from 'node:fs' -import process from 'node:process' import { join } from 'pathe' import { diagnostics } from '../diagnostics' import { RolldownLogsManager } from '../rolldown/logs-manager' @@ -10,15 +9,11 @@ const weakMap = new WeakMap() export function getLogsManager(context: ViteDevToolsNodeContext): RolldownLogsManager { let manager = weakMap.get(context)! if (!manager) { - const dirs = [ - join(context.cwd, 'node_modules', '.rolldown'), - join(process.cwd(), 'node_modules', '.rolldown'), - ] - const dir = dirs.find(dir => existsSync(dir)) - if (!dir) { + const dir = join(context.cwd, 'node_modules', '.rolldown') + if (!existsSync(dir)) { diagnostics.RDDT0001() } - manager = new RolldownLogsManager(dir ?? dirs[0]!) + manager = new RolldownLogsManager(dir) } return manager } diff --git a/packages/rolldown/tsdown.config.ts b/packages/rolldown/tsdown.config.ts index 7c3f1c2d4..27b85a097 100644 --- a/packages/rolldown/tsdown.config.ts +++ b/packages/rolldown/tsdown.config.ts @@ -2,8 +2,9 @@ import { defineConfig } from 'tsdown' export default defineConfig({ entry: { - index: 'src/index.ts', - dirs: 'src/dirs.ts', + 'index': 'src/index.ts', + 'dirs': 'src/dirs.ts', + 'node/agent': 'src/node/agent/index.ts', }, tsconfig: '../../tsconfig.base.json', target: 'esnext', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b693bebd1..3a59f1079 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,6 +52,9 @@ catalogs: '@devframes/plugin-terminals': specifier: ^0.6.0 version: 0.6.0 + '@modelcontextprotocol/sdk': + specifier: ^1.29.0 + version: 1.29.0 actionspack: specifier: ^0.1.5 version: 0.1.5 @@ -445,7 +448,7 @@ importers: version: 3.2.4(@vitejs/devtools@0.3.4)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3)) '@nuxt/eslint': specifier: catalog:devtools - version: 1.16.0(@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.39)(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(magicast@0.5.2)(oxc-parser@0.133.0)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + version: 1.16.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.39)(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(magicast@0.5.2)(oxc-parser@0.133.0)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) '@types/chrome': specifier: catalog:types version: 0.2.2 @@ -547,7 +550,7 @@ importers: version: 8.1.4(@types/node@25.0.3)(@vitejs/devtools@0.3.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) vite-plugin-inspect: specifier: catalog:devtools - version: 12.0.0-beta.3(@nuxt/kit@4.4.8(magicast@0.5.2))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + version: 12.0.0-beta.3(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@nuxt/kit@4.4.8(magicast@0.5.2))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) vite-plugin-vue-tracer: specifier: catalog:playground version: 1.4.0(vite@8.1.4)(vue@3.5.39(typescript@6.0.3)) @@ -577,7 +580,7 @@ importers: version: 4.8.4(change-case@5.4.4)(focus-trap@8.2.2)(fuse.js@7.4.2)(idb-keyval@6.3.0)(typescript@6.0.3)(vite@8.1.4(@types/node@25.0.3)(@vitejs/devtools@packages+core)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0))(vitepress@2.0.0-alpha.18(@types/node@25.0.3)(@vitejs/devtools@packages+core)(change-case@5.4.4)(esbuild@0.28.1)(fuse.js@7.4.2)(idb-keyval@6.3.0)(jiti@2.7.0)(postcss@8.5.16)(terser@5.44.1)(tsx@4.23.0)(typescript@6.0.3)(yaml@2.9.0))(vue@3.5.39(typescript@6.0.3)) devframe: specifier: catalog:deps - version: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + version: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) mermaid: specifier: catalog:docs version: 11.16.0 @@ -721,16 +724,19 @@ importers: dependencies: '@devframes/hub': specifier: catalog:deps - version: 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)) + version: 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)) '@devframes/plugin-inspect': specifier: catalog:deps - version: 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) + version: 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) '@devframes/plugin-messages': specifier: catalog:deps - version: 0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4) + version: 0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4) '@devframes/plugin-terminals': specifier: catalog:deps - version: 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4) + version: 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4) + '@modelcontextprotocol/sdk': + specifier: catalog:deps + version: 1.29.0(zod@4.3.6) '@vitejs/devtools-kit': specifier: workspace:* version: link:../kit @@ -745,7 +751,7 @@ importers: version: 7.0.0 devframe: specifier: catalog:deps - version: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + version: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) h3: specifier: catalog:deps version: 2.0.1-rc.22(crossws@0.4.9(srvx@0.11.15)) @@ -809,10 +815,10 @@ importers: dependencies: '@devframes/hub': specifier: catalog:deps - version: 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)) + version: 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)) devframe: specifier: catalog:deps - version: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + version: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) mlly: specifier: catalog:deps version: 1.8.2 @@ -1086,7 +1092,7 @@ importers: version: 6.0.7(vite@8.1.4(@types/node@25.0.3)(@vitejs/devtools@packages+core)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0))(vue@3.5.39(typescript@5.9.3)) devframe: specifier: catalog:deps - version: 0.6.0(srvx@0.11.15)(typescript@5.9.3) + version: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@5.9.3) storybook: specifier: catalog:storybook version: 10.4.6(@testing-library/dom@10.4.1)(@types/react@19.2.17)(prettier@2.8.8)(react@19.2.7) @@ -1727,6 +1733,12 @@ packages: '@floating-ui/vue@1.1.9': resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + 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'} @@ -1869,6 +1881,16 @@ packages: '@mermaid-js/parser@1.2.0': resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -4803,6 +4825,10 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -4846,6 +4872,14 @@ packages: ajv: optional: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-keywords@5.1.0: resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: @@ -5029,6 +5063,10 @@ packages: birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -5273,6 +5311,18 @@ packages: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -5285,12 +5335,24 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -6083,6 +6145,14 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + 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'} @@ -6095,6 +6165,16 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -6160,6 +6240,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -6199,6 +6283,10 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -6369,6 +6457,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hono@4.12.30: + resolution: {integrity: sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==} + engines: {node: '>=16.9.0'} + hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -6415,6 +6507,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + idb-keyval@6.3.0: resolution: {integrity: sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow==} @@ -6478,6 +6574,14 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -6549,6 +6653,9 @@ packages: is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -6597,6 +6704,9 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + js-stringify@1.0.2: resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} @@ -6642,6 +6752,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-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -7008,10 +7121,18 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7253,6 +7374,10 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -7353,6 +7478,10 @@ packages: object-deep-merge@2.0.1: resolution: {integrity: sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + obug@2.1.3: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} @@ -7378,6 +7507,9 @@ packages: resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} engines: {node: '>= 0.8'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -7529,6 +7661,9 @@ packages: path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -7553,6 +7688,10 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -7791,6 +7930,10 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + publint@0.3.21: resolution: {integrity: sha512-OqejcnMV6E9zel2oCrUOJEiiFkGiAAni0A6ibfQNh1k9Gu5z4F+Yso8lllam7AzmV6Do0vp7u3UpZNRBwuXaHQ==} engines: {node: '>=18'} @@ -7840,6 +7983,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -7863,6 +8010,10 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc9@3.0.1: resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} @@ -8028,6 +8179,10 @@ packages: roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -8137,6 +8292,22 @@ packages: resolution: {integrity: sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==} engines: {node: '>=20'} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -8556,6 +8727,10 @@ packages: resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==} engines: {node: '>=20'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + type-level-regexp@0.1.17: resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} @@ -8655,6 +8830,10 @@ packages: '@unocss/webpack': optional: true + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin-utils@0.3.1: resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} engines: {node: '>=20.19.0'} @@ -9208,6 +9387,9 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.21.0: resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} @@ -9294,6 +9476,11 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} @@ -9607,10 +9794,10 @@ snapshots: '@colordx/core@5.4.3': {} - '@devframes/hub@0.5.4(devframe@0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': + '@devframes/hub@0.5.4(devframe@0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': dependencies: birpc: 4.0.0 - devframe: 0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + devframe: 0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) nostics: 0.2.0(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) pathe: 2.0.3 perfect-debounce: 2.1.0 @@ -9626,40 +9813,40 @@ snapshots: - vite - webpack - '@devframes/hub@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))': + '@devframes/hub@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))': dependencies: birpc: 4.0.0 destr: 2.0.5 - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) nostics: 1.1.4 pathe: 2.0.3 perfect-debounce: 2.1.0 tinyexec: 1.2.4 zigpty: 0.2.1 - '@devframes/plugin-inspect@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4)': + '@devframes/plugin-inspect@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4)': dependencies: '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) nostics: 1.1.4 optionalDependencies: vite: 8.1.4(@types/node@25.0.3)(@vitejs/devtools@0.3.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) transitivePeerDependencies: - valibot - '@devframes/plugin-messages@0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4)': + '@devframes/plugin-messages@0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4)': dependencies: - '@devframes/hub': 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)) - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + '@devframes/hub': 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) nostics: 1.1.4 optionalDependencies: vite: 8.1.4(@types/node@25.0.3)(@vitejs/devtools@0.3.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) - '@devframes/plugin-terminals@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4)': + '@devframes/plugin-terminals@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4)': dependencies: '@xterm/addon-fit': 0.11.0 '@xterm/xterm': 6.0.0 - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) nostics: 1.1.4 pathe: 2.0.3 valibot: 1.4.2(typescript@6.0.3) @@ -9871,12 +10058,12 @@ snapshots: dependencies: '@eslint/core': 1.2.1 - '@eslint/config-inspector@3.0.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': + '@eslint/config-inspector@3.0.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': dependencies: ansis: 4.3.1 cac: 7.0.0 chokidar: 5.0.0 - devframe: 0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + devframe: 0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) eslint: 10.6.0(jiti@2.7.0) jiti: 2.7.0 tinyglobby: 0.2.17 @@ -9951,6 +10138,10 @@ snapshots: - '@vue/composition-api' - vue + '@hono/node-server@1.19.14(hono@4.12.30)': + dependencies: + hono: 4.12.30 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -10134,6 +10325,28 @@ snapshots: dependencies: '@chevrotain/types': 11.1.2 + '@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.30) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.30 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.11.1 @@ -10269,7 +10482,7 @@ snapshots: which: 6.0.1 ws: 8.21.0 optionalDependencies: - '@vitejs/devtools': 0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) transitivePeerDependencies: - bufferutil - supports-color @@ -10316,9 +10529,9 @@ snapshots: - supports-color - typescript - '@nuxt/eslint@1.16.0(@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.39)(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(magicast@0.5.2)(oxc-parser@0.133.0)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': + '@nuxt/eslint@1.16.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.39)(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(magicast@0.5.2)(oxc-parser@0.133.0)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': dependencies: - '@eslint/config-inspector': 3.0.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@eslint/config-inspector': 3.0.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(eslint@10.6.0(jiti@2.7.0))(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) '@nuxt/devtools-kit': 3.2.4(magicast@0.5.2)(vite@8.1.4) '@nuxt/eslint-config': 1.16.0(@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.39)(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) '@nuxt/eslint-plugin': 1.16.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) @@ -12456,11 +12669,11 @@ snapshots: - rollup - supports-color - '@vitejs/devtools-kit@0.3.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': + '@vitejs/devtools-kit@0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': dependencies: - '@devframes/hub': 0.5.4(devframe@0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@devframes/hub': 0.5.4(devframe@0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) birpc: 4.0.0 - devframe: 0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + devframe: 0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) mlly: 1.8.2 nostics: 1.1.4 pathe: 2.0.3 @@ -12482,10 +12695,10 @@ snapshots: - utf-8-validate - webpack - '@vitejs/devtools-kit@0.4.1(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)': + '@vitejs/devtools-kit@0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)': dependencies: - '@devframes/hub': 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)) - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + '@devframes/hub': 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) mlly: 1.8.2 nostics: 1.1.4 vite: 8.1.4(@types/node@25.0.3)(@vitejs/devtools@0.4.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) @@ -12495,15 +12708,15 @@ snapshots: - typescript optional: true - '@vitejs/devtools-rolldown@0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))(webpack@5.104.1(esbuild@0.28.1))': + '@vitejs/devtools-rolldown@0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))(webpack@5.104.1(esbuild@0.28.1))': dependencies: '@floating-ui/dom': 1.7.6 '@rolldown/debug': 1.1.5 - '@vitejs/devtools-kit': 0.3.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools-kit': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) birpc: 4.0.0 cac: 7.0.0 d3-shape: 3.2.0 - devframe: 0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + devframe: 0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) diff: 9.0.0 get-port-please: 3.2.0 h3: 2.0.1-rc.22(crossws@0.4.9(srvx@0.11.15)) @@ -12555,11 +12768,11 @@ snapshots: - webpack optional: true - '@vitejs/devtools-rolldown@0.4.1(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))': + '@vitejs/devtools-rolldown@0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))': dependencies: '@floating-ui/dom': 1.7.6 '@rolldown/debug': 1.1.5 - '@vitejs/devtools-kit': 0.4.1(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4) + '@vitejs/devtools-kit': 0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4) d3-shape: 3.2.0 diff: 9.0.0 nostics: 1.1.4 @@ -12573,14 +12786,14 @@ snapshots: - vue optional: true - '@vitejs/devtools@0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': + '@vitejs/devtools@0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1))': dependencies: - '@devframes/hub': 0.5.4(devframe@0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) - '@vitejs/devtools-kit': 0.3.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) - '@vitejs/devtools-rolldown': 0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))(webpack@5.104.1(esbuild@0.28.1)) + '@devframes/hub': 0.5.4(devframe@0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools-kit': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools-rolldown': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3))(webpack@5.104.1(esbuild@0.28.1)) birpc: 4.0.0 cac: 7.0.0 - devframe: 0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + devframe: 0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) h3: 2.0.1-rc.22(crossws@0.4.9(srvx@0.11.15)) mlly: 1.8.2 nostics: 1.1.4 @@ -12626,17 +12839,17 @@ snapshots: - webpack optional: true - '@vitejs/devtools@0.4.1(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4)': + '@vitejs/devtools@0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4)': dependencies: - '@devframes/hub': 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)) - '@devframes/plugin-inspect': 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) - '@devframes/plugin-messages': 0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4) - '@devframes/plugin-terminals': 0.6.0(devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4) - '@vitejs/devtools-kit': 0.4.1(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4) - '@vitejs/devtools-rolldown': 0.4.1(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3)) + '@devframes/hub': 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)) + '@devframes/plugin-inspect': 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) + '@devframes/plugin-messages': 0.6.0(@devframes/hub@0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)))(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(vite@8.1.4) + '@devframes/plugin-terminals': 0.6.0(devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3))(typescript@6.0.3)(vite@8.1.4) + '@vitejs/devtools-kit': 0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4) + '@vitejs/devtools-rolldown': 0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3)(vite@8.1.4)(vue@3.5.39(typescript@6.0.3)) birpc: 4.0.0 cac: 7.0.0 - devframe: 0.6.0(srvx@0.11.15)(typescript@6.0.3) + devframe: 0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3) h3: 2.0.1-rc.22(crossws@0.4.9(srvx@0.11.15)) mlly: 1.8.2 nostics: 1.1.4 @@ -13205,6 +13418,11 @@ snapshots: dependencies: event-target-shim: 5.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -13234,6 +13452,10 @@ snapshots: optionalDependencies: ajv: 8.18.0 + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: ajv: 8.18.0 @@ -13403,6 +13625,20 @@ snapshots: birpc@4.0.0: {} + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} boxen@7.0.0: @@ -13648,6 +13884,12 @@ snapshots: content-disposition@0.5.2: {} + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.3: {} @@ -13656,12 +13898,21 @@ snapshots: cookie-es@3.1.1: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + core-js-compat@3.49.0: dependencies: browserslist: 4.28.2 core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -14007,7 +14258,7 @@ snapshots: devalue@5.8.1: {} - devframe@0.5.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)): + devframe@0.5.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)): dependencies: '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) birpc: 4.0.0 @@ -14018,6 +14269,8 @@ snapshots: pathe: 2.0.3 valibot: 1.4.2(typescript@6.0.3) ws: 8.21.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -14033,7 +14286,7 @@ snapshots: - vite - webpack - devframe@0.6.0(srvx@0.11.15)(typescript@5.9.3): + devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@5.9.3): dependencies: '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) birpc: 4.0.0 @@ -14046,11 +14299,13 @@ snapshots: pathe: 2.0.3 ufo: 1.6.4 valibot: 1.4.2(typescript@5.9.3) + optionalDependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) transitivePeerDependencies: - srvx - typescript - devframe@0.6.0(srvx@0.11.15)(typescript@6.0.3): + devframe@0.6.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(srvx@0.11.15)(typescript@6.0.3): dependencies: '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) birpc: 4.0.0 @@ -14063,6 +14318,8 @@ snapshots: pathe: 2.0.3 ufo: 1.6.4 valibot: 1.4.2(typescript@6.0.3) + optionalDependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) transitivePeerDependencies: - srvx - typescript @@ -14557,6 +14814,12 @@ snapshots: events@3.3.0: {} + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -14583,6 +14846,44 @@ snapshots: expect-type@1.3.0: {} + express-rate-limit@8.5.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.8: {} extend-shallow@2.0.1: @@ -14641,6 +14942,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up-simple@1.0.1: {} find-up@5.0.0: @@ -14679,6 +14991,8 @@ snapshots: format@0.2.2: {} + forwarded@0.2.0: {} + fraction.js@5.3.4: {} fresh@2.0.0: {} @@ -14852,6 +15166,8 @@ snapshots: he@1.2.0: {} + hono@4.12.30: {} + hookable@5.5.3: {} hookable@6.1.1: {} @@ -14891,6 +15207,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + idb-keyval@6.3.0: {} ieee754@1.2.1: {} @@ -14955,6 +15275,10 @@ snapshots: transitivePeerDependencies: - supports-color + ip-address@10.2.0: {} + + ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} is-builtin-module@5.0.0: @@ -15005,6 +15329,8 @@ snapshots: is-promise@2.2.2: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.9 @@ -15050,6 +15376,8 @@ snapshots: jiti@2.7.0: {} + jose@6.2.3: {} + js-stringify@1.0.2: {} js-tokens@4.0.0: {} @@ -15084,6 +15412,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} @@ -15511,10 +15841,14 @@ snapshots: mdurl@2.0.0: {} + media-typer@1.1.0: {} + merge-anything@5.1.7: dependencies: is-what: 4.1.16 + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -15852,6 +16186,8 @@ snapshots: negotiator@0.6.4: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} nitropack@2.13.4(idb-keyval@6.3.0)(oxc-parser@0.133.0)(rolldown@1.1.5)(srvx@0.11.15)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)): @@ -16167,6 +16503,8 @@ snapshots: object-deep-merge@2.0.1: {} + object-inspect@1.13.4: {} + obug@2.1.3: {} ofetch@1.5.1: @@ -16187,6 +16525,10 @@ snapshots: on-headers@1.1.0: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -16506,6 +16848,8 @@ snapshots: path-to-regexp@3.3.0: {} + path-to-regexp@8.4.2: {} + pathe@1.1.2: {} pathe@2.0.3: {} @@ -16520,6 +16864,8 @@ snapshots: picomatch@4.0.5: {} + pkce-challenge@5.0.1: {} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -16747,6 +17093,11 @@ snapshots: property-information@7.1.0: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + publint@0.3.21: dependencies: '@publint/pack': 0.1.4 @@ -16826,6 +17177,11 @@ snapshots: punycode@2.3.1: {} + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + quansync@0.2.11: {} quansync@1.0.0: {} @@ -16842,6 +17198,13 @@ snapshots: range-parser@1.2.1: {} + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + rc9@3.0.1: dependencies: defu: 6.1.7 @@ -17063,6 +17426,16 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + run-applescript@7.1.0: {} run-parallel@1.2.0: @@ -17200,6 +17573,34 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -17545,7 +17946,7 @@ snapshots: tree-kill: 1.2.2 unconfig-core: 7.5.0 optionalDependencies: - '@vitejs/devtools': 0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) publint: 0.3.21 tsx: 4.23.0 typescript: 6.0.3 @@ -17574,7 +17975,7 @@ snapshots: tree-kill: 1.2.2 unconfig-core: 7.5.0 optionalDependencies: - '@vitejs/devtools': 0.4.1(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) + '@vitejs/devtools': 0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) publint: 0.3.21 tsx: 4.23.0 typescript: 6.0.3 @@ -17670,6 +18071,12 @@ snapshots: dependencies: tagged-tag: 1.0.0 + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + type-level-regexp@0.1.17: {} typescript@5.9.3: {} @@ -17825,6 +18232,8 @@ snapshots: transitivePeerDependencies: - vite + unpipe@1.0.0: {} + unplugin-utils@0.3.1: dependencies: pathe: 2.0.3 @@ -18074,9 +18483,9 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-inspect@12.0.0-beta.3(@nuxt/kit@4.4.8(magicast@0.5.2))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)): + vite-plugin-inspect@12.0.0-beta.3(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@nuxt/kit@4.4.8(magicast@0.5.2))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)): dependencies: - '@vitejs/devtools-kit': 0.3.4(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools-kit': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) ansis: 4.3.1 error-stack-parser-es: 1.0.5 obug: 2.1.3 @@ -18137,7 +18546,7 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.0.3 - '@vitejs/devtools': 0.3.4(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) + '@vitejs/devtools': 0.3.4(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(db0@0.3.4)(esbuild@0.28.1)(idb-keyval@6.3.0)(ioredis@5.10.1)(rolldown@1.1.5)(rollup@4.60.2)(typescript@6.0.3)(vite@8.1.4)(webpack@5.104.1(esbuild@0.28.1)) esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 @@ -18154,7 +18563,7 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.0.3 - '@vitejs/devtools': 0.4.1(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) + '@vitejs/devtools': 0.4.1(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(crossws@0.4.9(srvx@0.11.15))(srvx@0.11.15)(typescript@6.0.3)(valibot@1.4.2(typescript@6.0.3))(vite@8.1.4) esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 @@ -18535,6 +18944,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + wrappy@1.0.2: {} + ws@8.21.0: {} wsl-utils@0.1.0: @@ -18635,6 +19046,10 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 + zod-to-json-schema@3.25.2(zod@4.3.6): + dependencies: + zod: 4.3.6 + zod@4.3.6: {} zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 12bcbfc27..677668c72 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -61,6 +61,7 @@ catalogs: '@devframes/plugin-inspect': ^0.6.0 '@devframes/plugin-messages': ^0.6.0 '@devframes/plugin-terminals': ^0.6.0 + '@modelcontextprotocol/sdk': ^1.29.0 '@rolldown/debug': ^1.1.5 actionspack: ^0.1.5 birpc: ^4.0.0 diff --git a/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.d.ts b/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.d.ts new file mode 100644 index 000000000..f66291436 --- /dev/null +++ b/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.d.ts @@ -0,0 +1,7 @@ +/** + * Generated by tsnapi — public API snapshot of `@vitejs/devtools-rolldown/node/agent` + */ +// #region Functions +export declare function DevToolsRolldownAgent(): PluginWithDevTools; +export declare function registerRolldownAgentTools(_: ViteDevToolsNodeContext): void; +// #endregion \ No newline at end of file diff --git a/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.js b/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.js new file mode 100644 index 000000000..3328d2f9e --- /dev/null +++ b/test/__snapshots__/tsnapi/@vitejs/devtools-rolldown/node/agent.snapshot.js @@ -0,0 +1,7 @@ +/** + * Generated by tsnapi — public API snapshot of `@vitejs/devtools-rolldown/node/agent` + */ +// #region Functions +export function DevToolsRolldownAgent() {} +export function registerRolldownAgentTools(_) {} +// #endregion \ No newline at end of file diff --git a/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.d.ts b/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.d.ts index 5fc89c50b..777ea986d 100644 --- a/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.d.ts +++ b/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.d.ts @@ -8,6 +8,9 @@ export interface BuildOptions { outDir: string; base: string; } +export interface McpOptions { + root?: string; +} export interface StartOptions { root?: string; config?: string; @@ -19,5 +22,6 @@ export interface StartOptions { // #region Functions export declare function build(_: BuildOptions): Promise; +export declare function mcp(_: McpOptions): Promise; export declare function start(_: StartOptions): Promise; // #endregion \ No newline at end of file diff --git a/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.js b/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.js index 0c44dafb4..efd591622 100644 --- a/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.js +++ b/test/__snapshots__/tsnapi/@vitejs/devtools/cli-commands.snapshot.js @@ -3,5 +3,6 @@ */ // #region Functions export async function build(_) {} +export async function mcp(_) {} export async function start(_) {} // #endregion \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index 3174c9df5..a1a2911ac 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -36,6 +36,9 @@ "@vitejs/devtools-kit": [ "./packages/kit/src/index.ts" ], + "@vitejs/devtools-rolldown/node/agent": [ + "./packages/rolldown/src/node/agent/index.ts" + ], "@vitejs/devtools-rolldown": [ "./packages/rolldown/src/index.ts" ],