@xiaou66/vite-plugin-vue-mcp-next 0.0.2 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/plugin/createPlugin.ts","../src/shared/limits.ts","../src/constants.ts","../src/context.ts","../src/shared/ringBuffer.ts","../src/mcp/createMcpServer.ts","../src/mcp/tools/console.ts","../src/mcp/routeTools.ts","../src/cdp/cdpClient.ts","../src/cdp/targetMatcher.ts","../src/mcp/tools/dom.ts","../src/cdp/cdpDom.ts","../src/mcp/tools/evaluate.ts","../src/cdp/cdpEvaluate.ts","../src/mcp/tools/network.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/pages.ts","../src/mcp/tools/vue.ts","../src/mcp/transport.ts","../src/mcp/vueRpc.ts","../src/cdp/cdpConsole.ts","../src/shared/serialization.ts","../src/cdp/cdpNetwork.ts","../src/shared/sanitize.ts","../src/shared/url.ts","../src/plugin/cdpLifecycle.ts","../src/plugin/injectRuntime.ts","../src/plugin/mcpClientConfig/index.ts","../src/plugin/mcpClientConfig/codexConfig.ts","../src/plugin/mcpClientConfig/jsonConfig.ts"],"sourcesContent":["/**\n * vite-plugin-vue-mcp-next 的公开入口。\n *\n * 入口文件只负责导出插件工厂和类型,具体实现放在 `plugin/createPlugin`,\n * 避免后续 MCP、CDP、Runtime 逻辑把公开 API 文件变成大文件。\n */\nexport { vueMcpNext, vueMcpNext as default } from './plugin/createPlugin'\nexport type {\n CdpOptions,\n ConsoleOptions,\n ConsoleRecord,\n CursorMcpConfig,\n DomOptions,\n EvaluateOptions,\n McpClientConfigOptions,\n NetworkOptions,\n NetworkRecord,\n PageTarget,\n ResolvedVueMcpNextOptions,\n RuntimeMode,\n RuntimeOptions,\n VueMcpNextContext,\n VueMcpNextOptions\n} from './types'\n","import type { Plugin, ResolvedConfig } from 'vite'\nimport { searchForWorkspaceRoot } from 'vite'\nimport { mergeOptions } from '../constants'\nimport { createVueMcpNextContext } from '../context'\nimport { createMcpServer } from '../mcp/createMcpServer'\nimport { setupMcpTransport } from '../mcp/transport'\nimport { createServerVueRuntimeRpc } from '../mcp/vueRpc'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n VueMcpNextOptions\n} from '../types'\nimport { createCdpLifecycleController } from './cdpLifecycle'\nimport { createRuntimeInjectionController } from './injectRuntime'\nimport { updateMcpClientConfigs } from './mcpClientConfig'\nimport { createRPCServer } from 'vite-dev-rpc'\n\n/**\n * 创建 vite-plugin-vue-mcp-next 插件。\n *\n * 这里只编排 Vite 生命周期,把 MCP、Runtime、CDP 等细节交给独立模块,\n * 避免插件入口随着能力增加而变成难以测试的大文件。\n */\nexport function vueMcpNext(userOptions: VueMcpNextOptions = {}): Plugin {\n const options = mergeOptions(userOptions)\n const ctx = createVueMcpNextContext(options)\n let config: ResolvedConfig | undefined\n const runtimeInjection = createRuntimeInjectionController(\n options,\n () => config\n )\n const cdpLifecycle = createCdpLifecycleController(ctx)\n ctx.cdpLifecycle = cdpLifecycle\n\n return {\n name: 'vite-plugin-vue-mcp-next',\n enforce: 'pre',\n apply: 'serve',\n configResolved(resolvedConfig) {\n config = resolvedConfig\n },\n async configureServer(server) {\n ctx.rpcServer = createRPCServer(\n 'vite-plugin-vue-mcp-next',\n server.ws,\n createServerVueRuntimeRpc(ctx),\n {\n timeout: -1\n }\n )\n const mcpServer = createMcpServer(ctx, server)\n setupMcpTransport(options.mcpPath, mcpServer, server)\n server.ws.on(\n 'vite-plugin-vue-mcp-next:page-connected',\n (payload: unknown) => {\n if (isRuntimePageTarget(payload)) {\n ctx.pages.upsert(payload)\n void cdpLifecycle.connectPage(payload)\n }\n }\n )\n server.ws.on(\n 'vite-plugin-vue-mcp-next:console-record',\n (payload: unknown) => {\n if (isConsoleRecord(payload)) {\n ctx.consoleRecords.push(payload)\n }\n }\n )\n server.ws.on(\n 'vite-plugin-vue-mcp-next:network-record',\n (payload: unknown) => {\n if (isNetworkRecord(payload)) {\n ctx.networkRecords.push(payload)\n }\n }\n )\n\n const port = String(server.config.server.port || 5173)\n const mcpUrl = `http://${options.host}:${port}${options.mcpPath}/sse`\n const root = searchForWorkspaceRoot(server.config.root)\n await updateMcpClientConfigs(root, mcpUrl, options.mcpClients)\n\n if (options.printUrl) {\n setTimeout(() => {\n console.log(` ➜ MCP: Server is running at ${mcpUrl}`)\n }, 300)\n }\n\n server.httpServer?.once('close', () => {\n void cdpLifecycle.closeAll()\n })\n },\n resolveId(importee) {\n return runtimeInjection.resolveId(importee)\n },\n load(id) {\n return runtimeInjection.load(id)\n },\n transform(code, id, transformOptions) {\n return runtimeInjection.transform(code, id, transformOptions?.ssr)\n },\n transformIndexHtml(html) {\n return runtimeInjection.transformIndexHtml(html)\n }\n }\n}\n\n/**\n * 校验 runtime 页面上报载荷。\n *\n * Vite WebSocket 事件来自浏览器运行时,服务端不能直接信任 unknown payload;\n * 只校验页面注册所需字段,可以让后续扩展 readyState、viewport 等额外字段时不破坏注册流程。\n */\nfunction isRuntimePageTarget(payload: unknown): payload is PageTarget {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<PageTarget>\n\n return (\n target.source === 'runtime' &&\n typeof target.pageId === 'string' &&\n typeof target.url === 'string' &&\n typeof target.pathname === 'string' &&\n typeof target.connected === 'boolean'\n )\n}\n\n/**\n * 校验 console hook 上报记录。\n *\n * Console 日志来自浏览器页面,服务端只接收最小必需字段,避免异常 payload 污染日志缓存。\n */\nfunction isConsoleRecord(payload: unknown): payload is ConsoleRecord {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const record = payload as Partial<ConsoleRecord>\n\n return (\n typeof record.id === 'string' &&\n typeof record.pageId === 'string' &&\n record.source === 'hook' &&\n isConsoleLevel(record.level) &&\n typeof record.message === 'string' &&\n typeof record.timestamp === 'number'\n )\n}\n\n/**\n * 校验 Console 日志级别。\n *\n * 显式枚举可以避免浏览器端传入任意字符串后影响 MCP 过滤逻辑。\n */\nfunction isConsoleLevel(level: unknown): level is ConsoleRecord['level'] {\n return (\n level === 'log' ||\n level === 'info' ||\n level === 'warn' ||\n level === 'error' ||\n level === 'debug'\n )\n}\n\n/**\n * 校验 network hook 上报记录。\n *\n * Network 记录可能包含响应体和请求体,服务端先校验路由所需字段,后续再由工具层做展示裁剪。\n */\nfunction isNetworkRecord(payload: unknown): payload is NetworkRecord {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const record = payload as Partial<NetworkRecord>\n\n return (\n typeof record.id === 'string' &&\n typeof record.pageId === 'string' &&\n record.source === 'hook' &&\n typeof record.url === 'string' &&\n typeof record.method === 'string' &&\n typeof record.startedAt === 'number'\n )\n}\n","/**\n * 运行时采集的默认限制集中定义。\n *\n * DOM、Console 和 Network 都可能持续产生大量数据;把限制放在共享模块里,\n * 可以让服务端工具、运行时 Hook 和测试使用同一套安全边界。\n */\n\n/** 默认 DOM 递归深度,保留主要结构,同时避免复杂页面把 MCP 上下文撑爆。 */\nexport const DEFAULT_DOM_MAX_DEPTH = 8\n\n/** 默认 DOM 节点上限,用于防止一次性返回整页巨量节点。 */\nexport const DEFAULT_DOM_MAX_NODES = 2000\n\n/** 默认文本截断长度,保留可定位内容但避免长文案污染调试上下文。 */\nexport const DEFAULT_DOM_MAX_TEXT_LENGTH = 300\n\n/** 默认 Console 缓存上限,适合开发态持续运行且不会无界增长。 */\nexport const DEFAULT_CONSOLE_MAX_RECORDS = 1000\n\n/** 默认 Network 缓存上限,覆盖常见调试窗口同时控制内存占用。 */\nexport const DEFAULT_NETWORK_MAX_RECORDS = 500\n\n/** 默认请求体和响应体最大采集长度,避免大文件响应进入 MCP 工具结果。 */\nexport const DEFAULT_NETWORK_MAX_BODY_SIZE = 100_000\n\n/**\n * 默认脱敏 header。\n *\n * 这些字段通常包含认证态或用户隐私,Network 工具默认隐藏它们可以降低误传风险。\n */\nexport const DEFAULT_MASK_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie'\n] as const\n\n/** 默认响应体截断标记,集中定义可以让 Hook 和 CDP 输出保持一致。 */\nexport const TRUNCATED_MARKER = '[truncated]'\n","import {\n DEFAULT_CONSOLE_MAX_RECORDS,\n DEFAULT_DOM_MAX_DEPTH,\n DEFAULT_DOM_MAX_NODES,\n DEFAULT_DOM_MAX_TEXT_LENGTH,\n DEFAULT_MASK_HEADERS,\n DEFAULT_NETWORK_MAX_BODY_SIZE,\n DEFAULT_NETWORK_MAX_RECORDS\n} from './shared/limits'\nimport type {\n McpClientConfigOptions,\n ResolvedVueMcpNextOptions,\n VueMcpNextOptions\n} from './types'\n\n/** 默认 MCP 挂载路径,使用双下划线前缀避免与业务路由冲突。 */\nexport const DEFAULT_MCP_PATH = '/__mcp'\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n getPageState: 'get_page_state',\n getDomTree: 'get_dom_tree',\n queryDom: 'query_dom',\n getConsoleLogs: 'get_console_logs',\n clearConsoleLogs: 'clear_console_logs',\n evaluateScript: 'evaluate_script',\n getNetworkRequests: 'get_network_requests',\n getNetworkRequestDetail: 'get_network_request_detail',\n clearNetworkRequests: 'clear_network_requests',\n getComponentTree: 'get_component_tree',\n getComponentState: 'get_component_state',\n editComponentState: 'edit_component_state',\n highlightComponent: 'highlight_component',\n getRouterInfo: 'get_router_info',\n getPiniaTree: 'get_pinia_tree',\n getPiniaState: 'get_pinia_state'\n} as const\n\n/** 虚拟模块 ID 集中管理,便于注入逻辑和测试复用。 */\nexport const VIRTUAL_RUNTIME_ID = 'virtual:vite-plugin-vue-mcp-next/runtime'\n\n/** Vite 内部解析虚拟模块时需要使用的空字节前缀。 */\nexport const RESOLVED_VIRTUAL_RUNTIME_ID = `\\0${VIRTUAL_RUNTIME_ID}`\n\n/** 默认 MCP 客户端服务名,集中定义可以让旧 Cursor 配置和新多客户端配置保持一致。 */\nconst DEFAULT_MCP_CLIENT_SERVER_NAME = 'vue-mcp-next'\n\n/** 安全默认值,优先保证调试工具不会默认暴露危险能力。 */\nexport const DEFAULT_OPTIONS: ResolvedVueMcpNextOptions = {\n mcpPath: DEFAULT_MCP_PATH,\n host: 'localhost',\n printUrl: true,\n updateCursorMcpJson: {\n enabled: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n mcpClients: {\n cursor: true,\n codex: true,\n claudeCode: true,\n trae: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n runtime: {\n mode: 'auto',\n evaluate: {\n enabled: false,\n timeoutMs: 3000\n }\n },\n cdp: {},\n network: {\n mode: 'auto',\n maxRecords: DEFAULT_NETWORK_MAX_RECORDS,\n captureRequestBody: true,\n captureResponseBody: true,\n maxBodySize: DEFAULT_NETWORK_MAX_BODY_SIZE,\n maskHeaders: [...DEFAULT_MASK_HEADERS]\n },\n dom: {\n maxDepth: DEFAULT_DOM_MAX_DEPTH,\n maxNodes: DEFAULT_DOM_MAX_NODES,\n maxTextLength: DEFAULT_DOM_MAX_TEXT_LENGTH\n },\n console: {\n maxRecords: DEFAULT_CONSOLE_MAX_RECORDS\n }\n}\n\n/**\n * 兼容旧 Cursor 配置并合并新多客户端配置。\n *\n * `updateCursorMcpJson` 已经公开给用户,不能直接删除;这里让旧配置继续影响 Cursor,\n * 同时允许 `mcpClients` 作为新入口覆盖默认行为。\n */\nfunction mergeMcpClientOptions(\n cursorConfig: ResolvedVueMcpNextOptions['updateCursorMcpJson'],\n mcpClients?: McpClientConfigOptions\n): Required<McpClientConfigOptions> {\n return {\n ...DEFAULT_OPTIONS.mcpClients,\n cursor: cursorConfig.enabled,\n serverName: cursorConfig.serverName,\n ...mcpClients\n }\n}\n\n/**\n * 合并用户配置和安全默认值。\n *\n * 嵌套配置不能使用浅合并,否则用户只配置一个字段时会丢掉默认安全边界。\n */\nexport function mergeOptions(\n options: VueMcpNextOptions = {}\n): ResolvedVueMcpNextOptions {\n const cursorConfig =\n typeof options.updateCursorMcpJson === 'boolean'\n ? {\n enabled: options.updateCursorMcpJson,\n serverName: DEFAULT_OPTIONS.updateCursorMcpJson.serverName\n }\n : {\n ...DEFAULT_OPTIONS.updateCursorMcpJson,\n ...options.updateCursorMcpJson\n }\n const mcpClients = mergeMcpClientOptions(cursorConfig, options.mcpClients)\n\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n updateCursorMcpJson: cursorConfig,\n mcpClients,\n runtime: {\n ...DEFAULT_OPTIONS.runtime,\n ...options.runtime,\n evaluate: {\n ...DEFAULT_OPTIONS.runtime.evaluate,\n ...options.runtime?.evaluate\n }\n },\n cdp: {\n ...DEFAULT_OPTIONS.cdp,\n ...options.cdp\n },\n network: {\n ...DEFAULT_OPTIONS.network,\n ...options.network,\n maskHeaders: options.network?.maskHeaders ?? [\n ...DEFAULT_OPTIONS.network.maskHeaders\n ]\n },\n dom: {\n ...DEFAULT_OPTIONS.dom,\n ...options.dom\n },\n console: {\n ...DEFAULT_OPTIONS.console,\n ...options.console\n }\n }\n}\n","import { createHooks } from 'hookable'\nimport { createRingBuffer } from './shared/ringBuffer'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PageTargetRegistry,\n ResolvedVueMcpNextOptions,\n VueMcpNextContext\n} from './types'\n\n/**\n * 创建页面目标注册表。\n *\n * 独立工厂便于单元测试,也避免上下文对象承担过多数据结构细节。\n */\nexport function createPageTargetRegistry(): PageTargetRegistry {\n const targets = new Map<string, PageTarget>()\n\n return {\n upsert(target) {\n targets.set(target.pageId, target)\n },\n get(pageId) {\n return targets.get(pageId)\n },\n list() {\n return [...targets.values()]\n },\n disconnect(pageId) {\n const target = targets.get(pageId)\n\n if (!target) {\n return\n }\n\n targets.set(pageId, { ...target, connected: false })\n }\n }\n}\n\n/**\n * 创建插件运行时上下文。\n *\n * MCP、Runtime Bridge 和 CDP Adapter 都需要共享页面、日志和网络状态,\n * 但这些状态不应该散落在各工具文件里,否则工具之间会出现不一致。\n */\nexport function createVueMcpNextContext(\n options: ResolvedVueMcpNextOptions\n): VueMcpNextContext {\n return {\n options,\n hooks: createHooks(),\n rpcServer: undefined,\n pages: createPageTargetRegistry(),\n consoleRecords: createRingBuffer<ConsoleRecord>(options.console.maxRecords),\n networkRecords: createRingBuffer<NetworkRecord>(options.network.maxRecords)\n }\n}\n","/**\n * 提供固定容量的内存缓存。\n *\n * Console 和 Network 都是持续增长的数据源,使用环形缓存可以保证开发服务器长时间运行时\n * 内存占用仍然可控,同时保留最近的调试上下文。\n */\nexport interface RingBuffer<T> {\n /** 写入一条新记录,超过容量时会丢弃最早记录。 */\n push(value: T): void\n /** 返回按时间顺序排列的缓存快照,避免调用方直接修改内部数组。 */\n all(): T[]\n /** 清空缓存,适合 MCP clear 类工具使用。 */\n clear(): void\n}\n\n/**\n * 创建固定容量缓存。\n *\n * 这里不用外部依赖,避免核心调试缓存被复杂数据结构绑死。\n */\nexport function createRingBuffer<T>(capacity: number): RingBuffer<T> {\n const items: T[] = []\n\n return {\n push(value) {\n items.push(value)\n while (items.length > capacity) {\n items.shift()\n }\n },\n all() {\n return [...items]\n },\n clear() {\n items.length = 0\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ViteDevServer } from 'vite'\nimport type { VueMcpNextContext } from '../types'\nimport { registerConsoleTools } from './tools/console'\nimport { registerDomTools } from './tools/dom'\nimport { registerEvaluateTools } from './tools/evaluate'\nimport { registerNetworkTools } from './tools/network'\nimport { registerPageTools } from './tools/pages'\nimport { registerVueTools } from './tools/vue'\n\n/**\n * 创建 MCP Server 并注册所有工具。\n *\n * MCP 工具注册集中在这里,便于审查最终暴露给 AI 的能力范围,\n * 也方便后续按配置关闭高风险工具。\n */\nexport function createMcpServer(\n ctx: VueMcpNextContext,\n vite: ViteDevServer\n): McpServer {\n const server = new McpServer({\n name: 'vite-plugin-vue-mcp-next',\n version: '0.0.0'\n })\n\n registerPageTools(server, ctx, vite)\n registerDomTools(server, ctx)\n registerConsoleTools(server, ctx)\n registerEvaluateTools(server, ctx)\n registerNetworkTools(server, ctx)\n registerVueTools(server, ctx)\n\n return server\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolResponse } from '../routeTools'\n\n/**\n * 注册 Console 相关 MCP 工具。\n *\n * 日志采集会来自 CDP 和页面 Hook 两条通道,独立注册能让缓存和清理语义保持一致。\n */\nexport function registerConsoleTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getConsoleLogs,\n {\n description: 'Get console logs for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n level: z.enum(['log', 'info', 'warn', 'error', 'debug']).optional(),\n limit: z.number().optional()\n }\n },\n (input) => {\n const logs = ctx.consoleRecords\n .all()\n .filter((record) => !input.pageId || record.pageId === input.pageId)\n .filter((record) => !input.level || record.level === input.level)\n .slice(-(input.limit ?? ctx.options.console.maxRecords))\n\n return createToolResponse({ logs })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.clearConsoleLogs,\n {\n description: 'Clear cached console logs for the selected page.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n () => {\n ctx.consoleRecords.clear()\n\n return createToolResponse({ ok: true })\n }\n )\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { createCdpClient } from '../cdp/cdpClient'\nimport { matchCdpTarget } from '../cdp/targetMatcher'\nimport type { CdpTargetSummary } from '../cdp/targetMatcher'\nimport type {\n PageTarget,\n ResolvedVueMcpNextOptions,\n RuntimeMode,\n VueMcpNextContext\n} from '../types'\n\n/**\n * CDP 路由判断参数。\n *\n * 把判断输入收拢到对象中,可以避免后续工具增加条件时继续堆位置参数。\n */\nexport interface ShouldUseCdpOptions {\n /** 已解析配置,提供 runtime、network 和 cdp 开关。 */\n readonly options: ResolvedVueMcpNextOptions\n /** 当前工具是否已经找到匹配页面的 CDP target。 */\n readonly hasMatchedCdpTarget: boolean\n /** 当前能力自己的通道模式,例如 runtime.mode 或 network.mode。 */\n readonly capabilityMode: RuntimeMode | 'off'\n}\n\n/**\n * 判断通用 DevTools 能力是否应走 CDP。\n *\n * DOM、Console、Evaluate、Network 都遵循 CDP 优先但可回退的规则,\n * 集中判断可以避免各工具出现不一致的优先级。\n */\nexport function shouldUseCdp(options: ShouldUseCdpOptions): boolean {\n if (options.capabilityMode === 'off' || options.capabilityMode === 'hook') {\n return false\n }\n\n if (!options.hasMatchedCdpTarget) {\n return false\n }\n\n return Boolean(\n options.options.cdp.browserUrl || options.options.cdp.wsEndpoint\n )\n}\n\n/**\n * 创建 MCP 文本和结构化双格式响应。\n *\n * 同时返回 text 和 structuredContent,可以兼容通用 MCP 客户端展示和 AI 结构化读取。\n */\nexport function createToolResponse<T>(data: T) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }],\n structuredContent: data\n }\n}\n\n/**\n * 创建 MCP 错误响应。\n *\n * 工具失败时返回结构化错误,比直接抛异常更容易让 AI 解释下一步操作。\n */\nexport function createToolError(message: string, data?: unknown) {\n return createToolResponse({\n ok: false,\n error: message,\n data\n })\n}\n\n/**\n * 解析 MCP 工具目标页面。\n *\n * 多页面场景下用户可能不传 pageId,此时只能在唯一已连接页面时自动选择,\n * 避免工具误操作到错误页面。\n */\nexport function resolvePageTarget(\n ctx: VueMcpNextContext,\n pageId?: string\n): PageTarget {\n const targets = ctx.pages.list().filter((target) => target.connected)\n\n if (pageId) {\n const target = targets.find((item) => item.pageId === pageId)\n\n if (!target) {\n throw new Error(`Page target not found: ${pageId}`)\n }\n\n return target\n }\n\n if (targets.length === 1) {\n return targets[0]\n }\n\n throw new Error(\n 'Multiple or no page targets available. Call list_pages and pass pageId.'\n )\n}\n\n/**\n * 解析并连接当前页面对应的 CDP client。\n *\n * CDP 是可选通道,工具层需要按 pageId 或 targetUrlPattern 精确匹配,避免多 tab 场景下误连其他页面。\n */\nexport async function connectCdpForPage(\n ctx: VueMcpNextContext,\n pageId?: string\n): Promise<{ client: CDP.Client; target?: CdpTargetSummary } | undefined> {\n if (!ctx.options.cdp.browserUrl && !ctx.options.cdp.wsEndpoint) {\n return undefined\n }\n\n const cdp = createCdpClient(ctx.options.cdp)\n\n if (ctx.options.cdp.wsEndpoint) {\n return { client: await cdp.connect(ctx.options.cdp.wsEndpoint) }\n }\n\n const page = resolvePageTarget(ctx, pageId)\n const target = matchCdpTarget(await cdp.listTargets(), {\n url: page.url,\n targetUrlPattern: ctx.options.cdp.targetUrlPattern\n })\n\n if (!target?.webSocketDebuggerUrl) {\n return undefined\n }\n\n return { client: await cdp.connect(target.webSocketDebuggerUrl), target }\n}\n\n/**\n * 关闭 CDP client。\n *\n * 每次工具调用按需连接 CDP,结束后必须关闭,避免开发服务器长时间持有无用调试连接。\n */\nexport async function closeCdpClient(client: CDP.Client): Promise<void> {\n await client.close()\n}\n\n/**\n * 请求浏览器 Runtime Bridge 数据并等待一次回调。\n *\n * DOM 与 Evaluate 的 Hook fallback 需要从页面上下文读取数据,复用这里可以保证超时、\n * 并发事件隔离和错误结构在不同 MCP 工具之间保持一致。\n */\nexport async function requestRuntimeData(\n ctx: VueMcpNextContext,\n trigger: (event: string) => void\n): Promise<unknown> {\n if (!ctx.rpcServer) {\n return { ok: false, error: 'runtime bridge is not connected' }\n }\n\n const event = nanoid()\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n resolve({ ok: false, error: 'runtime bridge response timed out' })\n }, 5000)\n\n ctx.hooks.hookOnce(event, (data) => {\n clearTimeout(timeout)\n resolve(data)\n })\n trigger(event)\n })\n}\n","import CDP from 'chrome-remote-interface'\nimport type { CdpOptions } from '../types'\nimport type { CdpTargetSummary } from './targetMatcher'\n\n/**\n * CDP 客户端封装。\n *\n * 插件只连接用户提供的调试端点,不负责启动浏览器;封装该层可以隔离第三方库类型和连接细节。\n */\nexport interface CdpClient {\n /** 列出浏览器当前暴露的调试 target。 */\n listTargets(): Promise<CdpTargetSummary[]>\n /** 连接指定 WebSocket endpoint。 */\n connect(wsEndpoint: string): Promise<CDP.Client>\n}\n\n/**\n * 创建 CDP 客户端。\n *\n * browserUrl 和 wsEndpoint 支持不同接入方式:前者适合 Chrome remote debugging port,\n * 后者适合外部工具直接提供的页面 endpoint。\n */\nexport function createCdpClient(options: CdpOptions): CdpClient {\n return {\n async listTargets() {\n if (!options.browserUrl) {\n return []\n }\n\n const listUrl = new URL('/json/list', options.browserUrl)\n const response = await fetch(listUrl)\n\n return (await response.json()) as CdpTargetSummary[]\n },\n async connect(wsEndpoint) {\n return CDP({ target: wsEndpoint })\n }\n }\n}\n","/**\n * CDP target 摘要。\n *\n * CDP `/json/list` 返回字段很多,调试工具只需要这些字段来选择页面目标。\n */\nexport interface CdpTargetSummary {\n /** CDP target ID,用于连接和排查目标选择。 */\n readonly id: string\n /** target 类型,首版只处理 page,避免误连 service worker。 */\n readonly type: string\n /** target 当前 URL,用于和 runtime 页面建立关联。 */\n readonly url: string\n /** 页面标题,用于展示和调试。 */\n readonly title?: string\n /** 连接该 target 的 WebSocket 地址。 */\n readonly webSocketDebuggerUrl?: string\n}\n\n/**\n * CDP target 匹配参数。\n *\n * 多页面和多 tab 场景下不能随便选第一个 target,需要按 URL 和用户配置明确匹配。\n */\nexport interface MatchCdpTargetOptions {\n /** runtime 页面 URL,优先用于精确匹配。 */\n readonly url?: string\n /** 用户提供的 URL 匹配规则,用于 URL 不完全一致的代理或子路径场景。 */\n readonly targetUrlPattern?: string | RegExp\n}\n\n/**\n * 匹配可调试的 CDP 页面 target。\n *\n * 该函数只做纯匹配,不负责网络连接,便于测试多页面选择规则。\n */\nexport function matchCdpTarget(\n targets: readonly CdpTargetSummary[],\n options: MatchCdpTargetOptions\n): CdpTargetSummary | undefined {\n const pageTargets = targets.filter(\n (target) => target.type === 'page' && target.webSocketDebuggerUrl\n )\n\n if (options.url) {\n const exact = pageTargets.find((target) => target.url === options.url)\n if (exact) {\n return exact\n }\n }\n\n if (options.targetUrlPattern) {\n const pattern = options.targetUrlPattern\n\n return pageTargets.find((target) =>\n typeof pattern === 'string'\n ? target.url.includes(pattern)\n : pattern.test(target.url)\n )\n }\n\n return pageTargets[0]\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { cdpGetDomSnapshot, cdpQueryDom } from '../../cdp/cdpDom'\nimport type { VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolResponse,\n requestRuntimeData,\n shouldUseCdp\n} from '../routeTools'\n\n/**\n * 注册 DOM 相关 MCP 工具。\n *\n * DOM 能力后续会同时接 CDP 和页面 Hook,因此先独立成组,避免和 Vue 组件语义混在一起。\n */\nexport function registerDomTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getDomTree,\n {\n description: 'Get a clipped DOM tree for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n maxDepth: z.number().optional(),\n maxNodes: z.number().optional()\n }\n },\n async (input) => {\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const snapshot = await cdpGetDomSnapshot(cdp.client)\n\n return createToolResponse({\n source: 'cdp',\n snapshot,\n limits: {\n maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,\n maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes\n }\n })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const snapshot = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.getDomTree({\n event,\n maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,\n maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes,\n maxTextLength: ctx.options.dom.maxTextLength\n })\n })\n\n return createToolResponse({ source: 'hook', snapshot })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.queryDom,\n {\n description: 'Query DOM nodes by selector in the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n selector: z.string(),\n limit: z.number().optional()\n }\n },\n async (input) => {\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const nodes = await cdpQueryDom(\n cdp.client,\n input.selector,\n input.limit ?? 20\n )\n\n return createToolResponse({ source: 'cdp', nodes })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const nodes = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.queryDom({\n event,\n selector: input.selector,\n limit: input.limit ?? 20\n })\n })\n\n return createToolResponse({ source: 'hook', nodes })\n }\n )\n}\n","import type CDP from 'chrome-remote-interface'\n\n/**\n * 通过 CDP 获取 DOM 快照。\n *\n * CDP DOMSnapshot 更接近 DevTools 视角,配置了 CDP 时应优先使用它获取通用 DOM 能力。\n */\nexport async function cdpGetDomSnapshot(client: CDP.Client): Promise<unknown> {\n await client.DOMSnapshot.enable()\n\n return client.DOMSnapshot.captureSnapshot({\n computedStyles: []\n })\n}\n\n/**\n * 通过 CDP 查询 DOM。\n *\n * 使用 Runtime.evaluate 可以复用浏览器 selector 行为,并返回轻量可序列化摘要。\n */\nexport async function cdpQueryDom(\n client: CDP.Client,\n selector: string,\n limit: number\n): Promise<unknown> {\n const expression = `Array.from(document.querySelectorAll(${JSON.stringify(selector)})).slice(0, ${String(limit)}).map((el) => ({ tag: el.tagName.toLowerCase(), text: el.textContent?.trim() || '', attrs: Object.fromEntries(Array.from(el.attributes).map((attr) => [attr.name, attr.value])), rect: el.getBoundingClientRect().toJSON() }))`\n const result = await client.Runtime.evaluate({\n expression,\n returnByValue: true\n })\n\n if (result.exceptionDetails) {\n throw new Error(result.exceptionDetails.text || 'CDP query DOM failed')\n }\n\n return result.result.value\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { cdpEvaluate } from '../../cdp/cdpEvaluate'\nimport type { ResolvedVueMcpNextOptions, VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n shouldUseCdp\n} from '../routeTools'\n\n/**\n * 注册受控脚本执行工具。\n *\n * Evaluate 是高风险能力,先单独成组可以让后续默认关闭和权限提示逻辑更容易审查。\n */\nexport function registerEvaluateTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.evaluateScript,\n {\n description:\n 'Evaluate a script in the selected page when explicitly enabled.',\n inputSchema: {\n pageId: z.string().optional(),\n expression: z.string(),\n awaitPromise: z.boolean().optional()\n }\n },\n async (input) => {\n try {\n assertEvaluateEnabled(ctx.options)\n } catch (error) {\n return createToolError(\n error instanceof Error ? error.message : String(error)\n )\n }\n\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const value = await cdpEvaluate({\n client: cdp.client,\n expression: input.expression,\n awaitPromise: input.awaitPromise\n })\n\n return createToolResponse({ source: 'cdp', value })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.evaluateScript({\n event,\n expression: input.expression,\n awaitPromise: input.awaitPromise,\n timeoutMs: ctx.options.runtime.evaluate.timeoutMs\n })\n })\n\n return createToolResponse({ source: 'hook', result })\n }\n )\n}\n\n/**\n * 校验控制台执行是否已启用。\n *\n * evaluate_script 可以读取和修改页面状态,必须默认拒绝,避免 MCP 客户端无意中获得任意脚本执行能力。\n */\nexport function assertEvaluateEnabled(\n options: ResolvedVueMcpNextOptions\n): void {\n if (!options.runtime.evaluate.enabled) {\n throw new Error(\n 'evaluate_script is disabled. Enable runtime.evaluate.enabled to use it.'\n )\n }\n}\n","import type CDP from 'chrome-remote-interface'\n\n/**\n * CDP 脚本执行参数。\n *\n * 通过 CDP Runtime.evaluate 执行脚本更接近浏览器 DevTools Console 行为。\n */\nexport interface CdpEvaluateOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 要执行的表达式。 */\n readonly expression: string\n /** 是否等待 Promise 结果,适合调试异步页面状态。 */\n readonly awaitPromise?: boolean\n}\n\n/**\n * 使用 CDP 执行控制台表达式。\n *\n * 该能力只在用户显式开启 evaluate_script 后可用,避免默认暴露高风险操作。\n */\nexport async function cdpEvaluate(\n options: CdpEvaluateOptions\n): Promise<unknown> {\n const result = await options.client.Runtime.evaluate({\n expression: options.expression,\n awaitPromise: options.awaitPromise ?? true,\n returnByValue: true\n })\n\n if (result.exceptionDetails) {\n throw new Error(result.exceptionDetails.text || 'CDP evaluate failed')\n }\n\n return result.result.value\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolError, createToolResponse } from '../routeTools'\n\n/**\n * 注册 Network 相关 MCP 工具。\n *\n * 网络调试需要摘要、详情和清理三个入口,提前分组可以让后续 CDP/Hook 双通道实现只替换本文件。\n */\nexport function registerNetworkTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getNetworkRequests,\n {\n description: 'Get captured network request summaries.',\n inputSchema: {\n pageId: z.string().optional(),\n urlContains: z.string().optional(),\n method: z.string().optional(),\n status: z.number().optional(),\n limit: z.number().optional()\n }\n },\n (input) => {\n if (ctx.options.network.mode === 'off') {\n return createToolError(\n 'Network collection is disabled by configuration'\n )\n }\n\n const records = ctx.networkRecords\n .all()\n .filter((record) => !input.pageId || record.pageId === input.pageId)\n .filter(\n (record) =>\n !input.urlContains || record.url.includes(input.urlContains)\n )\n .filter(\n (record) =>\n !input.method ||\n record.method.toUpperCase() === input.method.toUpperCase()\n )\n .filter(\n (record) =>\n input.status === undefined || record.status === input.status\n )\n .slice(-(input.limit ?? ctx.options.network.maxRecords))\n\n return createToolResponse({ requests: records })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getNetworkRequestDetail,\n {\n description: 'Get captured network request detail by id.',\n inputSchema: { id: z.string() }\n },\n (input) => {\n if (ctx.options.network.mode === 'off') {\n return createToolError(\n 'Network collection is disabled by configuration'\n )\n }\n\n const record = ctx.networkRecords\n .all()\n .find((item) => item.id === input.id)\n\n return createToolResponse({ request: record ?? null })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.clearNetworkRequests,\n {\n description: 'Clear cached network requests.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n () => {\n ctx.networkRecords.clear()\n\n return createToolResponse({ ok: true })\n }\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { ViteDevServer } from 'vite'\nimport { normalizePath } from 'vite'\n\n/**\n * Vite 多入口页面描述。\n *\n * MCP 需要告诉 AI 当前项目有哪些可访问页面入口,而不仅仅是已经打开的浏览器页面。\n */\nexport interface VitePageEntry {\n /** Vite root 下的入口文件路径,用于解释页面来源。 */\n readonly file: string\n /** 浏览器访问路径,用于 MCP `list_pages` 输出。 */\n readonly pathname: string\n}\n\n/**\n * 发现 Vite HTML 页面入口。\n *\n * 多页 Vite 项目通常有多个 HTML 文件,该函数用轻量文件扫描补充已连接页面之外的入口列表。\n */\nexport function discoverHtmlEntries(server: ViteDevServer): VitePageEntry[] {\n const root = server.config.root\n const entries: VitePageEntry[] = []\n\n walkHtmlEntries(root, root, entries)\n\n return entries\n}\n\n/**\n * 递归扫描 HTML 入口。\n *\n * 扫描逻辑单独拆分,是为了让入口发现保持简单,同时避免主函数承担目录遍历细节。\n */\nfunction walkHtmlEntries(\n root: string,\n dir: string,\n entries: VitePageEntry[]\n): void {\n for (const item of fs.readdirSync(dir, { withFileTypes: true })) {\n if (item.name === 'node_modules' || item.name.startsWith('.')) {\n continue\n }\n\n const fullPath = path.join(dir, item.name)\n\n if (item.isDirectory()) {\n walkHtmlEntries(root, fullPath, entries)\n continue\n }\n\n if (!item.isFile() || !item.name.endsWith('.html')) {\n continue\n }\n\n const relative = normalizePath(path.relative(root, fullPath))\n entries.push({\n file: relative,\n pathname: relative === 'index.html' ? '/' : `/${relative}`\n })\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ViteDevServer } from 'vite'\nimport { createCdpClient } from '../../cdp/cdpClient'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { discoverHtmlEntries } from '../../plugin/entryDiscovery'\nimport type { PageTarget, VueMcpNextContext } from '../../types'\nimport { createToolResponse } from '../routeTools'\n\n/**\n * 注册页面目标相关 MCP 工具。\n *\n * 页面目标是所有调试工具的入口,先提供 list 能力可以让 AI 明确后续操作作用在哪个页面。\n */\nexport function registerPageTools(\n server: McpServer,\n ctx: VueMcpNextContext,\n vite: ViteDevServer\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.listPages,\n {\n description: 'List Vite page entries and connected runtime/CDP targets.'\n },\n async () => {\n const cdpResult = await listCdpPageTargets(ctx)\n\n for (const target of cdpResult.pages) {\n ctx.pages.upsert(target)\n void ctx.cdpLifecycle?.connectPage(target)\n }\n\n return createToolResponse({\n entries: discoverHtmlEntries(vite),\n pages: ctx.pages.list(),\n cdpError: cdpResult.error\n })\n }\n )\n}\n\n/**\n * 查询 CDP 暴露的页面 target。\n *\n * `list_pages` 是用户选择调试目标的入口,因此即使页面还没有 runtime bridge 连接,\n * 也应该展示 CDP 侧可见 target,方便纯 CDP 调试场景使用。\n */\nasync function listCdpPageTargets(ctx: VueMcpNextContext): Promise<{\n readonly pages: PageTarget[]\n readonly error?: string\n}> {\n if (ctx.options.cdp.wsEndpoint) {\n return { pages: [createWsEndpointTarget(ctx.options.cdp.wsEndpoint)] }\n }\n\n if (!ctx.options.cdp.browserUrl) {\n return { pages: [] }\n }\n\n try {\n const targets = await createCdpClient(ctx.options.cdp).listTargets()\n\n return {\n pages: targets\n .filter((target) => target.type === 'page')\n .map((target) => ({\n pageId: `cdp:${target.id}`,\n source: 'cdp',\n url: target.url,\n pathname: getPathname(target.url),\n title: target.title,\n connected: Boolean(target.webSocketDebuggerUrl)\n }))\n }\n } catch (error) {\n return {\n pages: [],\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 为直接传入 wsEndpoint 的场景创建虚拟页面。\n *\n * 直接 WebSocket endpoint 无法通过 `/json/list` 获取 URL,但仍然是合法 CDP 接入方式,\n * 因此用固定 pageId 暴露给 MCP 客户端,工具调用时会直接连接该 endpoint。\n */\nfunction createWsEndpointTarget(wsEndpoint: string): PageTarget {\n return {\n pageId: 'cdp:ws-endpoint',\n source: 'cdp',\n url: wsEndpoint,\n pathname: 'cdp:ws-endpoint',\n title: 'CDP WebSocket endpoint',\n connected: true\n }\n}\n\n/**\n * 从 URL 中提取 pathname。\n *\n * CDP target 可能包含 `about:blank` 等非标准页面 URL,解析失败时保留原值,\n * 这样 `list_pages` 不会因为浏览器临时页面导致整个工具失败。\n */\nfunction getPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport { nanoid } from 'nanoid'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolError, createToolResponse } from '../routeTools'\n\n/**\n * 注册 Vue 专属 MCP 工具。\n *\n * Vue 组件、Router 和 Pinia 使用 Runtime Bridge,不走 CDP;独立分组能防止通用 DevTools 路由误用到 Vue 语义。\n */\nexport function registerVueTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getComponentTree,\n { description: 'Get Vue component tree.' },\n async () =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getInspectorTree({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getComponentState,\n {\n description: 'Get Vue component state.',\n inputSchema: { componentName: z.string() }\n },\n async ({ componentName }) =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getInspectorState({ event, componentName })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.editComponentState,\n {\n description: 'Edit Vue component state.',\n inputSchema: {\n componentName: z.string(),\n path: z.array(z.string()),\n value: z.string(),\n valueType: z.enum(['string', 'number', 'boolean', 'object', 'array'])\n }\n },\n ({ componentName, path, value, valueType }) => {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n void ctx.rpcServer.editComponentState({\n componentName,\n path,\n value,\n valueType\n })\n return createToolResponse({ ok: true })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.highlightComponent,\n {\n description: 'Highlight a Vue component.',\n inputSchema: { componentName: z.string() }\n },\n ({ componentName }) => {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n void ctx.rpcServer.highlightComponent({ componentName })\n return createToolResponse({ ok: true })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getRouterInfo,\n { description: 'Get Vue Router information.' },\n async () =>\n requestVueData(ctx, (event) => {\n ctx.rpcServer?.getRouterInfo({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPiniaTree,\n { description: 'Get Pinia inspector tree.' },\n async () =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getPiniaTree({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPiniaState,\n {\n description: 'Get Pinia store state.',\n inputSchema: { storeName: z.string() }\n },\n async ({ storeName }) =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getPiniaState({ event, storeName })\n })\n )\n}\n\n/**\n * 请求 Vue Runtime Bridge 数据并等待回调。\n *\n * Vue 工具依赖浏览器页面在线,使用超时可以避免 MCP 客户端在页面未打开时永久等待。\n */\nasync function requestVueData(\n ctx: VueMcpNextContext,\n trigger: (event: string) => void\n): Promise<CallToolResult> {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n const event = nanoid()\n const data = await waitForVueHook(ctx, event, () => {\n trigger(event)\n })\n\n return {\n ...createToolResponse({ data })\n }\n}\n\n/**\n * 等待一次 Vue RPC 回调。\n *\n * 使用 hookOnce 保证同一个 event 只唤醒一个 MCP 请求,避免并发请求互相消费结果。\n */\nfunction waitForVueHook(\n ctx: VueMcpNextContext,\n event: string,\n trigger: () => void\n): Promise<unknown> {\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n resolve({ ok: false, error: 'Vue runtime bridge response timed out' })\n }, 5000)\n\n ctx.hooks.hookOnce(event, (data) => {\n clearTimeout(timeout)\n resolve(data)\n })\n trigger()\n })\n}\n\n/**\n * 返回 Vue bridge 不可用错误。\n *\n * 页面未打开或 runtime 尚未连接时,明确错误比空结果更容易让 AI 指导用户修复环境。\n */\nfunction vueBridgeUnavailable(): CallToolResult {\n return createToolError('Vue runtime bridge is not connected')\n}\n","/* eslint-disable @typescript-eslint/no-deprecated -- 当前需要兼容仍使用 /sse 与 /messages 的 MCP 客户端,Streamable HTTP 会在同一文件中后续扩展。 */\nimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ViteDevServer } from 'vite'\n\n/**\n * 在 Vite dev server 上挂载 MCP 路由。\n *\n * 当前保留 SSE 路由是为了兼容 Cursor 等仍使用 `/sse` 和 `/messages` 的 MCP 客户端;\n * 后续如果客户端统一转向 Streamable HTTP,可以在这里新增 `/mcp` 而不影响工具注册层。\n */\nexport function setupMcpTransport(\n base: string,\n server: McpServer,\n vite: ViteDevServer\n): void {\n const transports = new Map<string, SSEServerTransport>()\n\n vite.middlewares.use(`${base}/sse`, (_req, res) => {\n const transport = new SSEServerTransport(`${base}/messages`, res)\n transports.set(transport.sessionId, transport)\n res.on('close', () => {\n transports.delete(transport.sessionId)\n })\n void server.connect(transport).catch((error: unknown) => {\n res.destroy(error instanceof Error ? error : new Error(String(error)))\n })\n })\n\n vite.middlewares.use(`${base}/messages`, (req, res) => {\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.end('Method Not Allowed')\n return\n }\n\n const query = new URLSearchParams(req.url?.split('?').pop() || '')\n const sessionId = query.get('sessionId')\n\n if (!sessionId) {\n res.statusCode = 400\n res.end('Bad Request')\n return\n }\n\n const transport = transports.get(sessionId)\n\n if (!transport) {\n res.statusCode = 404\n res.end('Not Found')\n return\n }\n\n void transport.handlePostMessage(req, res).catch((error: unknown) => {\n res.destroy(error instanceof Error ? error : new Error(String(error)))\n })\n })\n}\n","import type { VueMcpNextContext, VueRuntimeRpc } from '../types'\n\n/**\n * 创建服务端 Vue RPC 回调对象。\n *\n * 浏览器端会调用 `on*Updated` 把 Vue DevTools 数据送回服务端,服务端再用 hook event\n * 唤醒对应 MCP 工具请求;这种事件名隔离可以避免并发请求互相串数据。\n */\nexport function createServerVueRuntimeRpc(\n ctx: VueMcpNextContext\n): VueRuntimeRpc {\n return {\n getDomTree: () => undefined,\n onDomTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n queryDom: () => undefined,\n onDomQueryUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n evaluateScript: () => undefined,\n onEvaluateScriptUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getInspectorTree: () => undefined,\n onInspectorTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getInspectorState: () => undefined,\n onInspectorStateUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n editComponentState: () => undefined,\n highlightComponent: () => undefined,\n getRouterInfo: () => undefined,\n onRouterInfoUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getPiniaTree: () => undefined,\n onPiniaTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getPiniaState: () => undefined,\n onPiniaInfoUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n }\n }\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { safeStringify } from '../shared/serialization'\nimport type { ConsoleRecord } from '../types'\n\n/**\n * CDP Console 监听参数。\n *\n * Console 事件来自浏览器 Runtime 层,比页面 Hook 更接近 DevTools Console。\n */\nexport interface CdpConsoleOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 页面 ID,用于和 runtime target 合并展示。 */\n readonly pageId: string\n /** 写入日志缓存的回调。 */\n readonly push: (record: ConsoleRecord) => void\n}\n\n/**\n * 启动 CDP Console 监听。\n *\n * 配置 CDP 后,日志能力优先使用该通道;Hook 仍保留早期日志和兜底能力。\n */\nexport async function startCdpConsole(\n options: CdpConsoleOptions\n): Promise<void> {\n await options.client.Runtime.enable()\n options.client.Runtime.consoleAPICalled((event) => {\n options.push({\n id: nanoid(),\n pageId: options.pageId,\n source: 'cdp',\n level: normalizeConsoleLevel(event.type),\n message: event.args\n .map((arg) => safeStringify(arg.value ?? arg.description))\n .join(' '),\n timestamp: event.timestamp\n })\n })\n}\n\n/**\n * 归一化 CDP 日志级别。\n *\n * CDP 使用 warning 等类型名,MCP 工具输出需要和浏览器 console 常见级别保持一致。\n */\nfunction normalizeConsoleLevel(level: string): ConsoleRecord['level'] {\n if (level === 'warning') {\n return 'warn'\n }\n\n if (level === 'error' || level === 'debug' || level === 'info') {\n return level\n }\n\n return 'log'\n}\n","/**\n * 将未知值转换为适合 MCP 文本输出的字符串。\n *\n * Console 参数、脚本执行结果和 Network body 都可能包含循环引用,统一序列化能避免工具调用崩溃。\n */\nexport function safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value\n }\n\n const seen = new WeakSet()\n\n const serialized = JSON.stringify(\n value,\n (_key: string, current: unknown): unknown => {\n if (typeof current !== 'object' || current === null) {\n return current\n }\n\n if (seen.has(current)) {\n return '[Circular]'\n }\n\n seen.add(current)\n return current\n }\n )\n\n return serialized\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { maskHeaders } from '../shared/sanitize'\nimport { parseRequestQuery } from '../shared/url'\nimport type { NetworkRecord } from '../types'\n\n/**\n * CDP Network 监听参数。\n *\n * CDP 能看到比 fetch/XHR Hook 更完整的请求生命周期,因此配置可用时优先使用该通道。\n */\nexport interface CdpNetworkOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 页面 ID,用于和 runtime target 合并展示。 */\n readonly pageId: string\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 是否采集响应体,响应体读取可能失败,不能影响请求记录。 */\n readonly captureResponseBody: boolean\n /** 写入网络缓存的回调。 */\n readonly push: (record: NetworkRecord) => void\n}\n\n/**\n * 启动 CDP Network 监听。\n *\n * 记录按 requestId 暂存,等 loadingFinished 或 loadingFailed 后再推送最终记录,\n * 这样可以把请求、响应和错误信息合并成一个 NetworkRecord。\n */\nexport async function startCdpNetwork(\n options: CdpNetworkOptions\n): Promise<void> {\n const records = new Map<string, NetworkRecord>()\n\n await options.client.Network.enable()\n options.client.Network.requestWillBeSent((event) => {\n records.set(event.requestId, {\n id: nanoid(),\n pageId: options.pageId,\n source: 'cdp',\n url: event.request.url,\n method: event.request.method,\n requestHeaders: maskHeaders(\n normalizeHeaders(event.request.headers),\n options.maskHeaders\n ),\n requestQuery: parseRequestQuery(event.request.url),\n requestBody: event.request.postData,\n startedAt: event.timestamp * 1000\n })\n })\n options.client.Network.responseReceived((event) => {\n const record = records.get(event.requestId)\n\n if (!record) {\n return\n }\n\n records.set(event.requestId, {\n ...record,\n status: event.response.status,\n responseHeaders: normalizeHeaders(event.response.headers)\n })\n })\n options.client.Network.loadingFinished((event) => {\n void finalizeCdpNetworkRecord(\n options,\n records,\n event.requestId,\n event.timestamp * 1000\n )\n })\n options.client.Network.loadingFailed((event) => {\n const record = records.get(event.requestId)\n\n if (!record) {\n return\n }\n\n records.delete(event.requestId)\n options.push({\n ...record,\n error: event.errorText,\n endedAt: event.timestamp * 1000,\n durationMs: event.timestamp * 1000 - record.startedAt\n })\n })\n}\n\n/**\n * 完成 CDP 网络记录。\n *\n * response body 可能因为跨域、缓存或 DevTools 限制读取失败,失败时只省略 body,不中断记录推送。\n */\nasync function finalizeCdpNetworkRecord(\n options: CdpNetworkOptions,\n records: Map<string, NetworkRecord>,\n requestId: string,\n endedAt: number\n): Promise<void> {\n const record = records.get(requestId)\n\n if (!record) {\n return\n }\n\n records.delete(requestId)\n options.push({\n ...record,\n responseBody: options.captureResponseBody\n ? await safeGetResponseBody(options.client, requestId)\n : undefined,\n endedAt,\n durationMs: endedAt - record.startedAt\n })\n}\n\n/**\n * 安全读取 CDP 响应体。\n *\n * CDP 的 getResponseBody 在部分请求上会失败,调试工具不能因为单个 body 失败丢掉整条请求。\n */\nasync function safeGetResponseBody(\n client: CDP.Client,\n requestId: string\n): Promise<string | undefined> {\n try {\n return (await client.Network.getResponseBody({ requestId })).body\n } catch {\n return undefined\n }\n}\n\n/**\n * 归一化 CDP headers。\n *\n * CDP header value 可能不是字符串,统一转字符串可以保持 NetworkRecord 可序列化。\n */\nfunction normalizeHeaders(\n headers: Record<string, unknown>\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).map(([key, value]) => [key, String(value)])\n )\n}\n","/**\n * 文本截断结果。\n *\n * MCP 输出需要明确告诉调用方内容被截断,否则 AI 可能误以为看到的是完整响应。\n */\nexport interface TruncatedText {\n /** 截断后的文本。 */\n readonly text: string\n /** 是否发生截断。 */\n readonly truncated: boolean\n /** 原始文本长度,用于判断丢失信息规模。 */\n readonly originalLength: number\n}\n\n/**\n * 截断长文本。\n *\n * DOM 文本和响应体都可能很大,统一截断策略可以避免不同工具输出行为不一致。\n */\nexport function truncateText(text: string, maxLength: number): TruncatedText {\n if (text.length <= maxLength) {\n return { text, truncated: false, originalLength: text.length }\n }\n\n return {\n text: text.slice(0, maxLength),\n truncated: true,\n originalLength: text.length\n }\n}\n\n/**\n * 对敏感 header 做脱敏。\n *\n * Network 调试需要展示 header,但认证和 Cookie 不应原样暴露给 AI 客户端。\n */\nexport function maskHeaders(\n headers: Record<string, string> = {},\n maskNames: readonly string[] = []\n): Record<string, string> {\n const normalizedMaskNames = new Set(\n maskNames.map((name) => name.toLowerCase())\n )\n\n return Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n normalizedMaskNames.has(name.toLowerCase()) ? '[masked]' : value\n ])\n )\n}\n","/**\n * 解析请求 URL 中的 query 参数。\n *\n * Network 工具需要直接回答“请求参数是什么”,将 query 拆成结构化对象可以减少 AI 重复解析。\n */\nexport function parseRequestQuery(\n url: string\n): Record<string, string | string[]> {\n const parsed = new URL(url, 'http://vite-plugin-vue-mcp-next.local')\n const queryEntries = new Map<string, string | string[]>()\n\n for (const [key, value] of parsed.searchParams.entries()) {\n const existing = queryEntries.get(key)\n\n if (existing === undefined) {\n queryEntries.set(key, value)\n continue\n }\n\n if (Array.isArray(existing)) {\n existing.push(value)\n continue\n }\n\n queryEntries.set(key, [existing, value])\n }\n\n return Object.fromEntries(queryEntries)\n}\n\n/**\n * 获取 URL pathname。\n *\n * 页面 target 可能上报绝对 URL 或相对路径,该 helper 让展示逻辑不需要关心来源格式。\n */\nexport function safeUrlPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url.split('?')[0] || '/'\n }\n}\n","import type CDP from 'chrome-remote-interface'\nimport { startCdpConsole } from '../cdp/cdpConsole'\nimport { createCdpClient } from '../cdp/cdpClient'\nimport { startCdpNetwork } from '../cdp/cdpNetwork'\nimport { matchCdpTarget } from '../cdp/targetMatcher'\nimport { shouldUseCdp } from '../mcp/routeTools'\nimport type {\n CdpLifecycleController,\n PageTarget,\n VueMcpNextContext\n} from '../types'\n\n/**\n * 创建 CDP 生命周期控制器。\n *\n * 该控制器只在用户配置 CDP 时工作;未配置时保持空操作,让 Hook 通道继续承担默认采集。\n */\nexport function createCdpLifecycleController(\n ctx: VueMcpNextContext\n): CdpLifecycleController {\n const clients = new Map<string, CDP.Client>()\n\n return {\n async connectPage(target) {\n if (clients.has(target.pageId) || !shouldStartCdp(ctx)) {\n return\n }\n\n const client = await safeConnectCdp(ctx, target)\n\n if (!client) {\n return\n }\n\n clients.set(target.pageId, client)\n try {\n await startCdpObservers(ctx, target, client)\n } catch (error) {\n clients.delete(target.pageId)\n await client.close()\n warnWhenCdpForced(ctx, error)\n }\n },\n async closeAll() {\n await Promise.all([...clients.values()].map((client) => client.close()))\n clients.clear()\n }\n }\n}\n\n/**\n * 判断是否需要启动 CDP 长连接。\n *\n * 只有 Console 或 Network 至少一个能力需要 CDP 时才建立连接,避免用户只配置 CDP 给 DOM/Evaluate\n * 按需使用时也被动占用浏览器调试连接。\n */\nfunction shouldStartCdp(ctx: VueMcpNextContext): boolean {\n const consoleUsesCdp = shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n const networkUsesCdp = shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.network.mode,\n hasMatchedCdpTarget: true\n })\n\n return consoleUsesCdp || networkUsesCdp\n}\n\n/**\n * 安全连接页面对应的 CDP target。\n *\n * `auto` 模式下 CDP 失败应回退到 Hook,不应打断 Vite 启动;`cdp` 模式的工具调用仍会返回明确错误。\n */\nasync function safeConnectCdp(\n ctx: VueMcpNextContext,\n target: PageTarget\n): Promise<CDP.Client | undefined> {\n try {\n return await connectCdp(ctx, target)\n } catch (error) {\n warnWhenCdpForced(ctx, error)\n\n return undefined\n }\n}\n\n/**\n * 只在强制 CDP 模式下输出警告。\n *\n * `auto` 模式的失败是预期回退路径,不应该污染普通开发日志;强制 CDP 则需要提示用户修正端点。\n */\nfunction warnWhenCdpForced(ctx: VueMcpNextContext, error: unknown): void {\n if (ctx.options.runtime.mode !== 'cdp' && ctx.options.network.mode !== 'cdp') {\n return\n }\n\n console.warn(\n `[vite-plugin-vue-mcp-next] CDP connect failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n )\n}\n\n/**\n * 连接指定页面的 CDP target。\n *\n * browserUrl 需要先发现 target 再连接;wsEndpoint 则认为用户已经完成目标选择,直接连接即可。\n */\nasync function connectCdp(\n ctx: VueMcpNextContext,\n target: PageTarget\n): Promise<CDP.Client | undefined> {\n const cdp = createCdpClient(ctx.options.cdp)\n\n if (ctx.options.cdp.wsEndpoint) {\n return cdp.connect(ctx.options.cdp.wsEndpoint)\n }\n\n if (!ctx.options.cdp.browserUrl) {\n return undefined\n }\n\n const matched = matchCdpTarget(await cdp.listTargets(), {\n url: target.url,\n targetUrlPattern: ctx.options.cdp.targetUrlPattern\n })\n\n if (!matched?.webSocketDebuggerUrl) {\n return undefined\n }\n\n return cdp.connect(matched.webSocketDebuggerUrl)\n}\n\n/**\n * 启动需要长连接的 CDP 监听器。\n *\n * DOM 和 Evaluate 是短请求能力,不在这里注册;Console 和 Network 必须持续监听才能捕获事件时间线。\n */\nasync function startCdpObservers(\n ctx: VueMcpNextContext,\n target: PageTarget,\n client: CDP.Client\n): Promise<void> {\n if (ctx.options.runtime.mode !== 'hook') {\n await startCdpConsole({\n client,\n pageId: target.pageId,\n push: (record) => {\n ctx.consoleRecords.push(record)\n }\n })\n }\n\n if (\n ctx.options.network.mode === 'auto' ||\n ctx.options.network.mode === 'cdp'\n ) {\n await startCdpNetwork({\n client,\n pageId: target.pageId,\n maskHeaders: ctx.options.network.maskHeaders,\n captureResponseBody: ctx.options.network.captureResponseBody,\n push: (record) => {\n ctx.networkRecords.push(record)\n }\n })\n }\n}\n","import type { IndexHtmlTransformResult, ResolvedConfig } from 'vite'\nimport { RESOLVED_VIRTUAL_RUNTIME_ID, VIRTUAL_RUNTIME_ID } from '../constants'\nimport type { ResolvedVueMcpNextOptions } from '../types'\n\n/**\n * 管理运行时脚本注入。\n *\n * Vite 项目可能使用 HTML 入口,也可能通过框架入口文件启动,\n * 因此注入逻辑必须同时支持 `transformIndexHtml` 和 `appendTo` 两种方式。\n */\nexport interface RuntimeInjectionController {\n /** 解析虚拟模块 ID,使浏览器端可以通过 Vite 加载 runtime client。 */\n resolveId(importee: string): string | undefined\n /** 加载 runtime client 模块内容。 */\n load(id: string): string | undefined\n /** 在 HTML 入口中注入 runtime client。 */\n transformIndexHtml(html: string): IndexHtmlTransformResult | undefined\n /** 在非 HTML 入口中追加 runtime import。 */\n transform(code: string, id: string, ssr?: boolean): string | undefined\n}\n\n/**\n * 创建运行时注入控制器。\n *\n * 将注入行为拆出 Vite 插件主文件,可以让后续测试单独覆盖 HTML 注入和 appendTo 注入。\n */\nexport function createRuntimeInjectionController(\n options: ResolvedVueMcpNextOptions,\n getConfig: () => ResolvedConfig | undefined\n): RuntimeInjectionController {\n return {\n resolveId(importee) {\n if (importee === VIRTUAL_RUNTIME_ID) {\n return RESOLVED_VIRTUAL_RUNTIME_ID\n }\n\n return undefined\n },\n load(id) {\n if (id !== RESOLVED_VIRTUAL_RUNTIME_ID) {\n return undefined\n }\n\n return \"import { startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';\\nvoid startRuntimeClient();\"\n },\n transformIndexHtml(html) {\n if (options.appendTo) {\n return undefined\n }\n\n const base = getConfig()?.base || '/'\n\n return {\n html,\n tags: [\n {\n tag: 'script',\n injectTo: 'head-prepend',\n attrs: {\n type: 'module',\n src: `${base}@id/${VIRTUAL_RUNTIME_ID}`\n }\n }\n ]\n }\n },\n transform(code, id, ssr) {\n if (ssr || !options.appendTo) {\n return undefined\n }\n\n const [filename] = id.split('?', 2)\n const matched =\n typeof options.appendTo === 'string'\n ? filename.endsWith(options.appendTo)\n : options.appendTo.test(filename)\n\n if (!matched) {\n return undefined\n }\n\n return `import '${VIRTUAL_RUNTIME_ID}';\\n${code}`\n }\n }\n}\n","import path from 'node:path'\nimport type { ResolvedVueMcpNextOptions } from '../../types'\nimport { updateCodexMcpClientConfig } from './codexConfig'\nimport { updateJsonMcpClientConfig } from './jsonConfig'\n\nexport { updateCodexMcpClientConfig } from './codexConfig'\nexport { updateJsonMcpClientConfig } from './jsonConfig'\n\n/** 多客户端 MCP 写入器只需要 resolved 后的 mcpClients 字段,测试可直接传入该字段。 */\nexport type ResolvedMcpClientConfigOptions =\n ResolvedVueMcpNextOptions['mcpClients']\n\n/**\n * 更新所有启用的项目级 MCP 客户端配置。\n *\n * 自动配置属于开发体验增强;每个客户端独立处理错误,避免某个配置文件损坏时影响 Vite 启动。\n */\nexport async function updateMcpClientConfigs(\n root: string,\n mcpUrl: string,\n options: ResolvedMcpClientConfigOptions\n): Promise<void> {\n const serverName = options.serverName\n const jobs: Promise<void>[] = []\n\n if (options.cursor) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Cursor',\n configPath: path.join(root, '.cursor', 'mcp.json'),\n mcpUrl,\n serverName\n })\n )\n }\n\n if (options.codex) {\n jobs.push(\n updateCodexMcpClientConfig({\n configPath: path.join(root, '.codex', 'config.toml'),\n mcpUrl,\n serverName\n })\n )\n }\n\n if (options.claudeCode) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Claude Code',\n configPath: path.join(root, '.mcp.json'),\n mcpUrl,\n serverName\n })\n )\n }\n\n if (options.trae) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Trae',\n configPath: path.join(root, '.trae', 'mcp.json'),\n mcpUrl,\n serverName\n })\n )\n }\n\n await Promise.all(jobs)\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/** Codex TOML 写入参数,集中承载可以避免后续扩展 env、headers 时增加位置参数。 */\nexport interface UpdateCodexMcpClientConfigOptions {\n /** 目标 `.codex/config.toml` 文件路径。 */\n readonly configPath: string\n /** 当前 Vite dev server 暴露的 MCP SSE 地址。 */\n readonly mcpUrl: string\n /** Codex 中展示的 MCP 服务名,只替换该服务对应 TOML 区块。 */\n readonly serverName: string\n}\n\n/**\n * 写入 Codex 项目级 MCP 配置。\n *\n * 这里不引入 TOML 解析依赖,是因为首版只需要管理本插件拥有的一个区块;\n * 区块替换能最大限度保留用户已有模型、沙箱和其他 MCP 配置的原始文本。\n */\nexport async function updateCodexMcpClientConfig(\n options: UpdateCodexMcpClientConfigOptions\n): Promise<void> {\n try {\n const current = await readOptionalTextFile(options.configPath)\n const next = replaceOrAppendOwnedBlock(current, options)\n\n await fs.mkdir(path.dirname(options.configPath), { recursive: true })\n await fs.writeFile(options.configPath, next)\n } catch (error) {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to update Codex MCP config at ${options.configPath}: ${formatError(error)}`\n )\n }\n}\n\nfunction replaceOrAppendOwnedBlock(\n current: string,\n options: UpdateCodexMcpClientConfigOptions\n): string {\n const block = createCodexServerBlock(options)\n const matcher = createOwnedBlockMatcher(options.serverName)\n\n if (matcher.test(current)) {\n return current.replace(matcher, block)\n }\n\n const separator = current.trim() ? '\\n\\n' : ''\n return `${trimEndNewline(current)}${separator}${block}`\n}\n\nfunction createCodexServerBlock(\n options: UpdateCodexMcpClientConfigOptions\n): string {\n return `${createTableHeader(options.serverName)}\\nurl = ${quoteTomlString(options.mcpUrl)}\\n`\n}\n\nfunction createOwnedBlockMatcher(serverName: string): RegExp {\n const plainHeader = escapeRegExp(`[mcp_servers.${serverName}]`)\n const quotedHeader = escapeRegExp(\n `[mcp_servers.${quoteTomlKey(serverName)}]`\n )\n\n return new RegExp(\n `(?:^|\\\\n)(?:${plainHeader}|${quotedHeader})\\\\n[\\\\s\\\\S]*?(?=\\\\n\\\\[|$)`\n )\n}\n\nfunction createTableHeader(serverName: string): string {\n const key = /^[A-Za-z0-9_-]+$/.test(serverName)\n ? serverName\n : quoteTomlKey(serverName)\n return `[mcp_servers.${key}]`\n}\n\nfunction quoteTomlKey(value: string): string {\n return quoteTomlString(value)\n}\n\nfunction quoteTomlString(value: string): string {\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n}\n\nasync function readOptionalTextFile(filePath: string): Promise<string> {\n try {\n return await fs.readFile(filePath, 'utf-8')\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return ''\n }\n\n throw error\n }\n}\n\nfunction trimEndNewline(value: string): string {\n return value.replace(/\\n+$/u, '')\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/** JSON MCP 配置写入参数,用对象承载可以避免客户端差异继续增加时拉长函数参数列表。 */\nexport interface UpdateJsonMcpClientConfigOptions {\n /** 客户端展示名,用于警告日志定位是哪一种配置失败。 */\n readonly clientName: string\n /** 目标配置文件路径,调用方负责传入项目级路径。 */\n readonly configPath: string\n /** 当前 Vite dev server 暴露的 MCP SSE 地址。 */\n readonly mcpUrl: string\n /** 写入 MCP 客户端的服务名,只更新该服务以保护用户已有配置。 */\n readonly serverName: string\n}\n\n/**\n * 写入 JSON 结构的项目级 MCP 配置。\n *\n * Cursor、Claude Code 和 Trae 都使用 `mcpServers` JSON 结构;共用该函数可以确保\n * “保留用户已有配置,只更新本插件条目”的行为在不同客户端中一致。\n */\nexport async function updateJsonMcpClientConfig(\n options: UpdateJsonMcpClientConfigOptions\n): Promise<void> {\n try {\n const config = await readJsonConfig(options.configPath)\n\n if (!isPlainRecord(config)) {\n warnConfigFailure(options, 'config root must be a JSON object')\n return\n }\n\n const mcpServers = isPlainRecord(config.mcpServers)\n ? config.mcpServers\n : {}\n mcpServers[options.serverName] = { url: options.mcpUrl }\n config.mcpServers = mcpServers\n\n await fs.mkdir(path.dirname(options.configPath), { recursive: true })\n await fs.writeFile(\n options.configPath,\n `${JSON.stringify(config, null, 2)}\\n`\n )\n } catch (error) {\n warnConfigFailure(options, formatError(error))\n }\n}\n\nasync function readJsonConfig(configPath: string): Promise<unknown> {\n const raw = await readOptionalTextFile(configPath)\n\n if (!raw.trim()) {\n return {}\n }\n\n return JSON.parse(raw)\n}\n\nasync function readOptionalTextFile(filePath: string): Promise<string> {\n try {\n return await fs.readFile(filePath, 'utf-8')\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return '{}'\n }\n\n throw error\n }\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction warnConfigFailure(\n options: UpdateJsonMcpClientConfigOptions,\n reason: string\n): void {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to update ${options.clientName} MCP config at ${options.configPath}: ${reason}`\n )\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error\n}\n"],"mappings":"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","names":["import_vite","CDP","import_zod","snapshot","nodes","import_zod","import_zod","fs","path","import_nanoid","import_zod","path","import_nanoid","import_nanoid","import_node_path","import_node_path","fs","path","import_promises","import_node_path","fs","path","formatError","readOptionalTextFile","isNodeError","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin/createPlugin.ts","../src/shared/limits.ts","../src/constants.ts","../src/context.ts","../src/shared/ringBuffer.ts","../src/mcp/createMcpServer.ts","../src/mcp/tools/console.ts","../src/mcp/routeTools.ts","../src/cdp/cdpClient.ts","../src/cdp/targetMatcher.ts","../src/mcp/tools/dom.ts","../src/cdp/cdpDom.ts","../src/mcp/tools/evaluate.ts","../src/cdp/cdpEvaluate.ts","../src/mcp/tools/network.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/pages.ts","../src/mcp/tools/screenshot.ts","../src/cdp/cdpScreenshot.ts","../src/mcp/tools/vue.ts","../src/mcp/transport.ts","../src/mcp/vueRpc.ts","../src/cdp/cdpConsole.ts","../src/shared/serialization.ts","../src/cdp/cdpNetwork.ts","../src/shared/sanitize.ts","../src/shared/url.ts","../src/plugin/cdpLifecycle.ts","../src/plugin/injectRuntime.ts","../src/plugin/mcpClientConfig/index.ts","../src/plugin/mcpClientConfig/codexConfig.ts","../src/plugin/mcpClientConfig/jsonConfig.ts"],"sourcesContent":["/**\n * vite-plugin-vue-mcp-next 的公开入口。\n *\n * 入口文件只负责导出插件工厂和类型,具体实现放在 `plugin/createPlugin`,\n * 避免后续 MCP、CDP、Runtime 逻辑把公开 API 文件变成大文件。\n */\nexport { vueMcpNext, vueMcpNext as default } from './plugin/createPlugin'\nexport type {\n CdpOptions,\n ConsoleOptions,\n ConsoleRecord,\n CursorMcpConfig,\n DomOptions,\n EvaluateOptions,\n McpClientConfigOptions,\n NetworkOptions,\n NetworkRecord,\n PageTarget,\n ResolvedVueMcpNextOptions,\n RuntimeMode,\n RuntimeOptions,\n VueMcpNextContext,\n VueMcpNextOptions\n} from './types'\n","import type { Plugin, ResolvedConfig } from 'vite'\nimport { searchForWorkspaceRoot } from 'vite'\nimport { mergeOptions } from '../constants'\nimport { createVueMcpNextContext } from '../context'\nimport { createMcpServer } from '../mcp/createMcpServer'\nimport { setupMcpTransport } from '../mcp/transport'\nimport { createServerVueRuntimeRpc } from '../mcp/vueRpc'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n VueMcpNextOptions\n} from '../types'\nimport { createCdpLifecycleController } from './cdpLifecycle'\nimport { createRuntimeInjectionController } from './injectRuntime'\nimport { updateMcpClientConfigs } from './mcpClientConfig'\nimport { createRPCServer } from 'vite-dev-rpc'\n\n/**\n * 创建 vite-plugin-vue-mcp-next 插件。\n *\n * 这里只编排 Vite 生命周期,把 MCP、Runtime、CDP 等细节交给独立模块,\n * 避免插件入口随着能力增加而变成难以测试的大文件。\n */\nexport function vueMcpNext(userOptions: VueMcpNextOptions = {}): Plugin {\n const options = mergeOptions(userOptions)\n const ctx = createVueMcpNextContext(options)\n let config: ResolvedConfig | undefined\n const runtimeInjection = createRuntimeInjectionController(\n options,\n () => config\n )\n const cdpLifecycle = createCdpLifecycleController(ctx)\n ctx.cdpLifecycle = cdpLifecycle\n\n return {\n name: 'vite-plugin-vue-mcp-next',\n enforce: 'pre',\n apply: 'serve',\n configResolved(resolvedConfig) {\n config = resolvedConfig\n },\n async configureServer(server) {\n ctx.rpcServer = createRPCServer(\n 'vite-plugin-vue-mcp-next',\n server.ws,\n createServerVueRuntimeRpc(ctx),\n {\n timeout: -1\n }\n )\n setupMcpTransport(\n options.mcpPath,\n () => createMcpServer(ctx, server),\n server\n )\n server.ws.on(\n 'vite-plugin-vue-mcp-next:page-connected',\n (payload: unknown) => {\n if (isRuntimePageTarget(payload)) {\n ctx.pages.upsert(payload)\n void cdpLifecycle.connectPage(payload)\n }\n }\n )\n server.ws.on(\n 'vite-plugin-vue-mcp-next:console-record',\n (payload: unknown) => {\n if (isConsoleRecord(payload)) {\n ctx.consoleRecords.push(payload)\n }\n }\n )\n server.ws.on(\n 'vite-plugin-vue-mcp-next:network-record',\n (payload: unknown) => {\n if (isNetworkRecord(payload)) {\n ctx.networkRecords.push(payload)\n }\n }\n )\n\n const port = String(server.config.server.port || 5173)\n const mcpSseUrl = `http://${options.host}:${port}${options.mcpPath}/sse`\n const mcpStreamableHttpUrl = `http://${options.host}:${port}${options.mcpPath}/mcp`\n const root = searchForWorkspaceRoot(server.config.root)\n await updateMcpClientConfigs(\n root,\n mcpSseUrl,\n mcpStreamableHttpUrl,\n options.mcpClients\n )\n\n if (options.printUrl) {\n setTimeout(() => {\n console.log(` ➜ MCP: SSE server is running at ${mcpSseUrl}`)\n console.log(\n ` ➜ MCP: Streamable HTTP server is running at ${mcpStreamableHttpUrl}`\n )\n }, 300)\n }\n\n server.httpServer?.once('close', () => {\n void cdpLifecycle.closeAll()\n })\n },\n resolveId(importee) {\n return runtimeInjection.resolveId(importee)\n },\n load(id) {\n return runtimeInjection.load(id)\n },\n transform(code, id, transformOptions) {\n return runtimeInjection.transform(code, id, transformOptions?.ssr)\n },\n transformIndexHtml(html) {\n return runtimeInjection.transformIndexHtml(html)\n }\n }\n}\n\n/**\n * 校验 runtime 页面上报载荷。\n *\n * Vite WebSocket 事件来自浏览器运行时,服务端不能直接信任 unknown payload;\n * 只校验页面注册所需字段,可以让后续扩展 readyState、viewport 等额外字段时不破坏注册流程。\n */\nfunction isRuntimePageTarget(payload: unknown): payload is PageTarget {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<PageTarget>\n\n return (\n target.source === 'runtime' &&\n typeof target.pageId === 'string' &&\n typeof target.url === 'string' &&\n typeof target.pathname === 'string' &&\n typeof target.connected === 'boolean'\n )\n}\n\n/**\n * 校验 console hook 上报记录。\n *\n * Console 日志来自浏览器页面,服务端只接收最小必需字段,避免异常 payload 污染日志缓存。\n */\nfunction isConsoleRecord(payload: unknown): payload is ConsoleRecord {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const record = payload as Partial<ConsoleRecord>\n\n return (\n typeof record.id === 'string' &&\n typeof record.pageId === 'string' &&\n record.source === 'hook' &&\n isConsoleLevel(record.level) &&\n typeof record.message === 'string' &&\n typeof record.timestamp === 'number'\n )\n}\n\n/**\n * 校验 Console 日志级别。\n *\n * 显式枚举可以避免浏览器端传入任意字符串后影响 MCP 过滤逻辑。\n */\nfunction isConsoleLevel(level: unknown): level is ConsoleRecord['level'] {\n return (\n level === 'log' ||\n level === 'info' ||\n level === 'warn' ||\n level === 'error' ||\n level === 'debug'\n )\n}\n\n/**\n * 校验 network hook 上报记录。\n *\n * Network 记录可能包含响应体和请求体,服务端先校验路由所需字段,后续再由工具层做展示裁剪。\n */\nfunction isNetworkRecord(payload: unknown): payload is NetworkRecord {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const record = payload as Partial<NetworkRecord>\n\n return (\n typeof record.id === 'string' &&\n typeof record.pageId === 'string' &&\n record.source === 'hook' &&\n typeof record.url === 'string' &&\n typeof record.method === 'string' &&\n typeof record.startedAt === 'number'\n )\n}\n","/**\n * 运行时采集的默认限制集中定义。\n *\n * DOM、Console 和 Network 都可能持续产生大量数据;把限制放在共享模块里,\n * 可以让服务端工具、运行时 Hook 和测试使用同一套安全边界。\n */\n\n/** 默认 DOM 递归深度,保留主要结构,同时避免复杂页面把 MCP 上下文撑爆。 */\nexport const DEFAULT_DOM_MAX_DEPTH = 8\n\n/** 默认 DOM 节点上限,用于防止一次性返回整页巨量节点。 */\nexport const DEFAULT_DOM_MAX_NODES = 2000\n\n/** 默认文本截断长度,保留可定位内容但避免长文案污染调试上下文。 */\nexport const DEFAULT_DOM_MAX_TEXT_LENGTH = 300\n\n/** 默认 Console 缓存上限,适合开发态持续运行且不会无界增长。 */\nexport const DEFAULT_CONSOLE_MAX_RECORDS = 1000\n\n/** 默认 Network 缓存上限,覆盖常见调试窗口同时控制内存占用。 */\nexport const DEFAULT_NETWORK_MAX_RECORDS = 500\n\n/** 默认请求体和响应体最大采集长度,避免大文件响应进入 MCP 工具结果。 */\nexport const DEFAULT_NETWORK_MAX_BODY_SIZE = 100_000\n\n/**\n * 默认脱敏 header。\n *\n * 这些字段通常包含认证态或用户隐私,Network 工具默认隐藏它们可以降低误传风险。\n */\nexport const DEFAULT_MASK_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie'\n] as const\n\n/** 默认响应体截断标记,集中定义可以让 Hook 和 CDP 输出保持一致。 */\nexport const TRUNCATED_MARKER = '[truncated]'\n","import {\n DEFAULT_CONSOLE_MAX_RECORDS,\n DEFAULT_DOM_MAX_DEPTH,\n DEFAULT_DOM_MAX_NODES,\n DEFAULT_DOM_MAX_TEXT_LENGTH,\n DEFAULT_MASK_HEADERS,\n DEFAULT_NETWORK_MAX_BODY_SIZE,\n DEFAULT_NETWORK_MAX_RECORDS\n} from './shared/limits'\nimport type {\n McpClientConfigOptions,\n ResolvedVueMcpNextOptions,\n VueMcpNextOptions\n} from './types'\n\n/** 默认 MCP 挂载路径,使用双下划线前缀避免与业务路由冲突。 */\nexport const DEFAULT_MCP_PATH = '/__mcp'\n\n/** 默认截图最大响应体积,避免 base64 图片挤占 MCP 客户端上下文。 */\nexport const DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n getPageState: 'get_page_state',\n getDomTree: 'get_dom_tree',\n queryDom: 'query_dom',\n takeScreenshot: 'take_screenshot',\n getConsoleLogs: 'get_console_logs',\n clearConsoleLogs: 'clear_console_logs',\n evaluateScript: 'evaluate_script',\n getNetworkRequests: 'get_network_requests',\n getNetworkRequestDetail: 'get_network_request_detail',\n clearNetworkRequests: 'clear_network_requests',\n getComponentTree: 'get_component_tree',\n getComponentState: 'get_component_state',\n editComponentState: 'edit_component_state',\n highlightComponent: 'highlight_component',\n getRouterInfo: 'get_router_info',\n getPiniaTree: 'get_pinia_tree',\n getPiniaState: 'get_pinia_state'\n} as const\n\n/** 虚拟模块 ID 集中管理,便于注入逻辑和测试复用。 */\nexport const VIRTUAL_RUNTIME_ID = 'virtual:vite-plugin-vue-mcp-next/runtime'\n\n/** Vite 内部解析虚拟模块时需要使用的空字节前缀。 */\nexport const RESOLVED_VIRTUAL_RUNTIME_ID = `\\0${VIRTUAL_RUNTIME_ID}`\n\n/** snapdom 扩展虚拟模块 ID,用静态 import 支持 Vite alias 和源码转换。 */\nexport const VIRTUAL_SCREENSHOT_CONFIG_ID =\n 'virtual:vite-plugin-vue-mcp-next/screenshot-config'\n\n/** Vite 内部解析截图配置虚拟模块时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID = `\\0${VIRTUAL_SCREENSHOT_CONFIG_ID}`\n\n/** 默认 MCP 客户端服务名,集中定义可以让旧 Cursor 配置和新多客户端配置保持一致。 */\nconst DEFAULT_MCP_CLIENT_SERVER_NAME = 'vue-mcp-next'\n\n/** 安全默认值,优先保证调试工具不会默认暴露危险能力。 */\nexport const DEFAULT_OPTIONS: ResolvedVueMcpNextOptions = {\n mcpPath: DEFAULT_MCP_PATH,\n host: 'localhost',\n printUrl: true,\n updateCursorMcpJson: {\n enabled: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n mcpClients: {\n cursor: true,\n codex: true,\n claudeCode: true,\n trae: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n runtime: {\n mode: 'auto',\n evaluate: {\n enabled: false,\n timeoutMs: 3000\n }\n },\n cdp: {},\n network: {\n mode: 'auto',\n maxRecords: DEFAULT_NETWORK_MAX_RECORDS,\n captureRequestBody: true,\n captureResponseBody: true,\n maxBodySize: DEFAULT_NETWORK_MAX_BODY_SIZE,\n maskHeaders: [...DEFAULT_MASK_HEADERS]\n },\n dom: {\n maxDepth: DEFAULT_DOM_MAX_DEPTH,\n maxNodes: DEFAULT_DOM_MAX_NODES,\n maxTextLength: DEFAULT_DOM_MAX_TEXT_LENGTH\n },\n console: {\n maxRecords: DEFAULT_CONSOLE_MAX_RECORDS\n },\n screenshot: {\n prefer: 'auto',\n maxBytes: DEFAULT_SCREENSHOT_MAX_BYTES,\n snapdom: {\n options: {},\n plugins: []\n }\n }\n}\n\n/**\n * 兼容旧 Cursor 配置并合并新多客户端配置。\n *\n * `updateCursorMcpJson` 已经公开给用户,不能直接删除;这里让旧配置继续影响 Cursor,\n * 同时允许 `mcpClients` 作为新入口覆盖默认行为。\n */\nfunction mergeMcpClientOptions(\n cursorConfig: ResolvedVueMcpNextOptions['updateCursorMcpJson'],\n mcpClients?: McpClientConfigOptions\n): Required<McpClientConfigOptions> {\n return {\n ...DEFAULT_OPTIONS.mcpClients,\n cursor: cursorConfig.enabled,\n serverName: cursorConfig.serverName,\n ...mcpClients\n }\n}\n\n/**\n * 合并用户配置和安全默认值。\n *\n * 嵌套配置不能使用浅合并,否则用户只配置一个字段时会丢掉默认安全边界。\n */\nexport function mergeOptions(\n options: VueMcpNextOptions = {}\n): ResolvedVueMcpNextOptions {\n const cursorConfig =\n typeof options.updateCursorMcpJson === 'boolean'\n ? {\n enabled: options.updateCursorMcpJson,\n serverName: DEFAULT_OPTIONS.updateCursorMcpJson.serverName\n }\n : {\n ...DEFAULT_OPTIONS.updateCursorMcpJson,\n ...options.updateCursorMcpJson\n }\n const mcpClients = mergeMcpClientOptions(cursorConfig, options.mcpClients)\n\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n updateCursorMcpJson: cursorConfig,\n mcpClients,\n runtime: {\n ...DEFAULT_OPTIONS.runtime,\n ...options.runtime,\n evaluate: {\n ...DEFAULT_OPTIONS.runtime.evaluate,\n ...options.runtime?.evaluate\n }\n },\n cdp: {\n ...DEFAULT_OPTIONS.cdp,\n ...options.cdp\n },\n network: {\n ...DEFAULT_OPTIONS.network,\n ...options.network,\n maskHeaders: options.network?.maskHeaders ?? [\n ...DEFAULT_OPTIONS.network.maskHeaders\n ]\n },\n dom: {\n ...DEFAULT_OPTIONS.dom,\n ...options.dom\n },\n console: {\n ...DEFAULT_OPTIONS.console,\n ...options.console\n },\n screenshot: {\n ...DEFAULT_OPTIONS.screenshot,\n ...options.screenshot,\n snapdom: {\n ...DEFAULT_OPTIONS.screenshot.snapdom,\n ...options.screenshot?.snapdom,\n options: {\n ...DEFAULT_OPTIONS.screenshot.snapdom.options,\n ...options.screenshot?.snapdom?.options\n },\n plugins:\n options.screenshot?.snapdom?.plugins ?? [\n ...DEFAULT_OPTIONS.screenshot.snapdom.plugins\n ]\n }\n }\n }\n}\n","import { createHooks } from 'hookable'\nimport { createRingBuffer } from './shared/ringBuffer'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PageTargetRegistry,\n ResolvedVueMcpNextOptions,\n VueMcpNextContext\n} from './types'\n\n/**\n * 创建页面目标注册表。\n *\n * 独立工厂便于单元测试,也避免上下文对象承担过多数据结构细节。\n */\nexport function createPageTargetRegistry(): PageTargetRegistry {\n const targets = new Map<string, PageTarget>()\n\n return {\n upsert(target) {\n targets.set(target.pageId, target)\n },\n get(pageId) {\n return targets.get(pageId)\n },\n list() {\n return [...targets.values()]\n },\n disconnect(pageId) {\n const target = targets.get(pageId)\n\n if (!target) {\n return\n }\n\n targets.set(pageId, { ...target, connected: false })\n }\n }\n}\n\n/**\n * 创建插件运行时上下文。\n *\n * MCP、Runtime Bridge 和 CDP Adapter 都需要共享页面、日志和网络状态,\n * 但这些状态不应该散落在各工具文件里,否则工具之间会出现不一致。\n */\nexport function createVueMcpNextContext(\n options: ResolvedVueMcpNextOptions\n): VueMcpNextContext {\n return {\n options,\n hooks: createHooks(),\n rpcServer: undefined,\n pages: createPageTargetRegistry(),\n consoleRecords: createRingBuffer<ConsoleRecord>(options.console.maxRecords),\n networkRecords: createRingBuffer<NetworkRecord>(options.network.maxRecords)\n }\n}\n","/**\n * 提供固定容量的内存缓存。\n *\n * Console 和 Network 都是持续增长的数据源,使用环形缓存可以保证开发服务器长时间运行时\n * 内存占用仍然可控,同时保留最近的调试上下文。\n */\nexport interface RingBuffer<T> {\n /** 写入一条新记录,超过容量时会丢弃最早记录。 */\n push(value: T): void\n /** 返回按时间顺序排列的缓存快照,避免调用方直接修改内部数组。 */\n all(): T[]\n /** 清空缓存,适合 MCP clear 类工具使用。 */\n clear(): void\n}\n\n/**\n * 创建固定容量缓存。\n *\n * 这里不用外部依赖,避免核心调试缓存被复杂数据结构绑死。\n */\nexport function createRingBuffer<T>(capacity: number): RingBuffer<T> {\n const items: T[] = []\n\n return {\n push(value) {\n items.push(value)\n while (items.length > capacity) {\n items.shift()\n }\n },\n all() {\n return [...items]\n },\n clear() {\n items.length = 0\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ViteDevServer } from 'vite'\nimport type { VueMcpNextContext } from '../types'\nimport { registerConsoleTools } from './tools/console'\nimport { registerDomTools } from './tools/dom'\nimport { registerEvaluateTools } from './tools/evaluate'\nimport { registerNetworkTools } from './tools/network'\nimport { registerPageTools } from './tools/pages'\nimport { registerScreenshotTools } from './tools/screenshot'\nimport { registerVueTools } from './tools/vue'\n\n/**\n * 创建 MCP Server 并注册所有工具。\n *\n * MCP 工具注册集中在这里,便于审查最终暴露给 AI 的能力范围,\n * 也方便后续按配置关闭高风险工具。\n */\nexport function createMcpServer(\n ctx: VueMcpNextContext,\n vite: ViteDevServer\n): McpServer {\n const server = new McpServer({\n name: 'vite-plugin-vue-mcp-next',\n version: '0.0.0'\n })\n\n registerPageTools(server, ctx, vite)\n registerDomTools(server, ctx)\n registerScreenshotTools(server, ctx)\n registerConsoleTools(server, ctx)\n registerEvaluateTools(server, ctx)\n registerNetworkTools(server, ctx)\n registerVueTools(server, ctx)\n\n return server\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolResponse } from '../routeTools'\n\n/**\n * 注册 Console 相关 MCP 工具。\n *\n * 日志采集会来自 CDP 和页面 Hook 两条通道,独立注册能让缓存和清理语义保持一致。\n */\nexport function registerConsoleTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getConsoleLogs,\n {\n description: 'Get console logs for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n level: z.enum(['log', 'info', 'warn', 'error', 'debug']).optional(),\n limit: z.number().optional()\n }\n },\n (input) => {\n const logs = ctx.consoleRecords\n .all()\n .filter((record) => !input.pageId || record.pageId === input.pageId)\n .filter((record) => !input.level || record.level === input.level)\n .slice(-(input.limit ?? ctx.options.console.maxRecords))\n\n return createToolResponse({ logs })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.clearConsoleLogs,\n {\n description: 'Clear cached console logs for the selected page.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n () => {\n ctx.consoleRecords.clear()\n\n return createToolResponse({ ok: true })\n }\n )\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { createCdpClient } from '../cdp/cdpClient'\nimport { matchCdpTarget } from '../cdp/targetMatcher'\nimport type { CdpTargetSummary } from '../cdp/targetMatcher'\nimport type {\n PageTarget,\n ResolvedVueMcpNextOptions,\n RuntimeMode,\n VueMcpNextContext\n} from '../types'\n\n/**\n * CDP 路由判断参数。\n *\n * 把判断输入收拢到对象中,可以避免后续工具增加条件时继续堆位置参数。\n */\nexport interface ShouldUseCdpOptions {\n /** 已解析配置,提供 runtime、network 和 cdp 开关。 */\n readonly options: ResolvedVueMcpNextOptions\n /** 当前工具是否已经找到匹配页面的 CDP target。 */\n readonly hasMatchedCdpTarget: boolean\n /** 当前能力自己的通道模式,例如 runtime.mode 或 network.mode。 */\n readonly capabilityMode: RuntimeMode | 'off'\n}\n\n/**\n * 判断通用 DevTools 能力是否应走 CDP。\n *\n * DOM、Console、Evaluate、Network 都遵循 CDP 优先但可回退的规则,\n * 集中判断可以避免各工具出现不一致的优先级。\n */\nexport function shouldUseCdp(options: ShouldUseCdpOptions): boolean {\n if (options.capabilityMode === 'off' || options.capabilityMode === 'hook') {\n return false\n }\n\n if (!options.hasMatchedCdpTarget) {\n return false\n }\n\n return Boolean(\n options.options.cdp.browserUrl || options.options.cdp.wsEndpoint\n )\n}\n\n/**\n * 创建 MCP 文本和结构化双格式响应。\n *\n * 同时返回 text 和 structuredContent,可以兼容通用 MCP 客户端展示和 AI 结构化读取。\n */\nexport function createToolResponse<T>(data: T) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }],\n structuredContent: data\n }\n}\n\n/**\n * 创建 MCP 错误响应。\n *\n * 工具失败时返回结构化错误,比直接抛异常更容易让 AI 解释下一步操作。\n */\nexport function createToolError(message: string, data?: unknown) {\n return createToolResponse({\n ok: false,\n error: message,\n data\n })\n}\n\n/**\n * 解析 MCP 工具目标页面。\n *\n * 多页面场景下用户可能不传 pageId,此时只能在唯一已连接页面时自动选择,\n * 避免工具误操作到错误页面。\n */\nexport function resolvePageTarget(\n ctx: VueMcpNextContext,\n pageId?: string\n): PageTarget {\n const targets = ctx.pages.list().filter((target) => target.connected)\n\n if (pageId) {\n const target = targets.find((item) => item.pageId === pageId)\n\n if (!target) {\n throw new Error(`Page target not found: ${pageId}`)\n }\n\n return target\n }\n\n if (targets.length === 1) {\n return targets[0]\n }\n\n throw new Error(\n 'Multiple or no page targets available. Call list_pages and pass pageId.'\n )\n}\n\n/**\n * 解析并连接当前页面对应的 CDP client。\n *\n * CDP 是可选通道,工具层需要按 pageId 或 targetUrlPattern 精确匹配,避免多 tab 场景下误连其他页面。\n */\nexport async function connectCdpForPage(\n ctx: VueMcpNextContext,\n pageId?: string\n): Promise<{ client: CDP.Client; target?: CdpTargetSummary } | undefined> {\n if (!ctx.options.cdp.browserUrl && !ctx.options.cdp.wsEndpoint) {\n return undefined\n }\n\n const cdp = createCdpClient(ctx.options.cdp)\n\n if (ctx.options.cdp.wsEndpoint) {\n return { client: await cdp.connect(ctx.options.cdp.wsEndpoint) }\n }\n\n const page = resolvePageTarget(ctx, pageId)\n const target = matchCdpTarget(await cdp.listTargets(), {\n url: page.url,\n targetUrlPattern: ctx.options.cdp.targetUrlPattern\n })\n\n if (!target?.webSocketDebuggerUrl) {\n return undefined\n }\n\n return { client: await cdp.connect(target.webSocketDebuggerUrl), target }\n}\n\n/**\n * 关闭 CDP client。\n *\n * 每次工具调用按需连接 CDP,结束后必须关闭,避免开发服务器长时间持有无用调试连接。\n */\nexport async function closeCdpClient(client: CDP.Client): Promise<void> {\n await client.close()\n}\n\n/**\n * 请求浏览器 Runtime Bridge 数据并等待一次回调。\n *\n * DOM 与 Evaluate 的 Hook fallback 需要从页面上下文读取数据,复用这里可以保证超时、\n * 并发事件隔离和错误结构在不同 MCP 工具之间保持一致。\n */\nexport async function requestRuntimeData(\n ctx: VueMcpNextContext,\n trigger: (event: string) => void\n): Promise<unknown> {\n if (!ctx.rpcServer) {\n return { ok: false, error: 'runtime bridge is not connected' }\n }\n\n const event = nanoid()\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n resolve({ ok: false, error: 'runtime bridge response timed out' })\n }, 5000)\n\n ctx.hooks.hookOnce(event, (data) => {\n clearTimeout(timeout)\n resolve(data)\n })\n trigger(event)\n })\n}\n","import CDP from 'chrome-remote-interface'\nimport type { CdpOptions } from '../types'\nimport type { CdpTargetSummary } from './targetMatcher'\n\n/**\n * CDP 客户端封装。\n *\n * 插件只连接用户提供的调试端点,不负责启动浏览器;封装该层可以隔离第三方库类型和连接细节。\n */\nexport interface CdpClient {\n /** 列出浏览器当前暴露的调试 target。 */\n listTargets(): Promise<CdpTargetSummary[]>\n /** 连接指定 WebSocket endpoint。 */\n connect(wsEndpoint: string): Promise<CDP.Client>\n}\n\n/**\n * 创建 CDP 客户端。\n *\n * browserUrl 和 wsEndpoint 支持不同接入方式:前者适合 Chrome remote debugging port,\n * 后者适合外部工具直接提供的页面 endpoint。\n */\nexport function createCdpClient(options: CdpOptions): CdpClient {\n return {\n async listTargets() {\n if (!options.browserUrl) {\n return []\n }\n\n const listUrl = new URL('/json/list', options.browserUrl)\n const response = await fetch(listUrl)\n\n return (await response.json()) as CdpTargetSummary[]\n },\n async connect(wsEndpoint) {\n return CDP({ target: wsEndpoint })\n }\n }\n}\n","/**\n * CDP target 摘要。\n *\n * CDP `/json/list` 返回字段很多,调试工具只需要这些字段来选择页面目标。\n */\nexport interface CdpTargetSummary {\n /** CDP target ID,用于连接和排查目标选择。 */\n readonly id: string\n /** target 类型,首版只处理 page,避免误连 service worker。 */\n readonly type: string\n /** target 当前 URL,用于和 runtime 页面建立关联。 */\n readonly url: string\n /** 页面标题,用于展示和调试。 */\n readonly title?: string\n /** 连接该 target 的 WebSocket 地址。 */\n readonly webSocketDebuggerUrl?: string\n}\n\n/**\n * CDP target 匹配参数。\n *\n * 多页面和多 tab 场景下不能随便选第一个 target,需要按 URL 和用户配置明确匹配。\n */\nexport interface MatchCdpTargetOptions {\n /** runtime 页面 URL,优先用于精确匹配。 */\n readonly url?: string\n /** 用户提供的 URL 匹配规则,用于 URL 不完全一致的代理或子路径场景。 */\n readonly targetUrlPattern?: string | RegExp\n}\n\n/**\n * 匹配可调试的 CDP 页面 target。\n *\n * 该函数只做纯匹配,不负责网络连接,便于测试多页面选择规则。\n */\nexport function matchCdpTarget(\n targets: readonly CdpTargetSummary[],\n options: MatchCdpTargetOptions\n): CdpTargetSummary | undefined {\n const pageTargets = targets.filter(\n (target) => target.type === 'page' && target.webSocketDebuggerUrl\n )\n\n if (options.url) {\n const exact = pageTargets.find((target) => target.url === options.url)\n if (exact) {\n return exact\n }\n }\n\n if (options.targetUrlPattern) {\n const pattern = options.targetUrlPattern\n\n return pageTargets.find((target) =>\n typeof pattern === 'string'\n ? target.url.includes(pattern)\n : pattern.test(target.url)\n )\n }\n\n return pageTargets[0]\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { cdpGetDomSnapshot, cdpQueryDom } from '../../cdp/cdpDom'\nimport type { VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolResponse,\n requestRuntimeData,\n shouldUseCdp\n} from '../routeTools'\n\n/**\n * 注册 DOM 相关 MCP 工具。\n *\n * DOM 能力后续会同时接 CDP 和页面 Hook,因此先独立成组,避免和 Vue 组件语义混在一起。\n */\nexport function registerDomTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getDomTree,\n {\n description: 'Get a clipped DOM tree for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n maxDepth: z.number().optional(),\n maxNodes: z.number().optional()\n }\n },\n async (input) => {\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const snapshot = await cdpGetDomSnapshot(cdp.client)\n\n return createToolResponse({\n source: 'cdp',\n snapshot,\n limits: {\n maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,\n maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes\n }\n })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const snapshot = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.getDomTree({\n event,\n maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,\n maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes,\n maxTextLength: ctx.options.dom.maxTextLength\n })\n })\n\n return createToolResponse({ source: 'hook', snapshot })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.queryDom,\n {\n description: 'Query DOM nodes by selector in the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n selector: z.string(),\n limit: z.number().optional()\n }\n },\n async (input) => {\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const nodes = await cdpQueryDom(\n cdp.client,\n input.selector,\n input.limit ?? 20\n )\n\n return createToolResponse({ source: 'cdp', nodes })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const nodes = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.queryDom({\n event,\n selector: input.selector,\n limit: input.limit ?? 20\n })\n })\n\n return createToolResponse({ source: 'hook', nodes })\n }\n )\n}\n","import type CDP from 'chrome-remote-interface'\n\n/**\n * 通过 CDP 获取 DOM 快照。\n *\n * CDP DOMSnapshot 更接近 DevTools 视角,配置了 CDP 时应优先使用它获取通用 DOM 能力。\n */\nexport async function cdpGetDomSnapshot(client: CDP.Client): Promise<unknown> {\n await client.DOMSnapshot.enable()\n\n return client.DOMSnapshot.captureSnapshot({\n computedStyles: []\n })\n}\n\n/**\n * 通过 CDP 查询 DOM。\n *\n * 使用 Runtime.evaluate 可以复用浏览器 selector 行为,并返回轻量可序列化摘要。\n */\nexport async function cdpQueryDom(\n client: CDP.Client,\n selector: string,\n limit: number\n): Promise<unknown> {\n const expression = `Array.from(document.querySelectorAll(${JSON.stringify(selector)})).slice(0, ${String(limit)}).map((el) => ({ tag: el.tagName.toLowerCase(), text: el.textContent?.trim() || '', attrs: Object.fromEntries(Array.from(el.attributes).map((attr) => [attr.name, attr.value])), rect: el.getBoundingClientRect().toJSON() }))`\n const result = await client.Runtime.evaluate({\n expression,\n returnByValue: true\n })\n\n if (result.exceptionDetails) {\n throw new Error(result.exceptionDetails.text || 'CDP query DOM failed')\n }\n\n return result.result.value\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { cdpEvaluate } from '../../cdp/cdpEvaluate'\nimport type { ResolvedVueMcpNextOptions, VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n shouldUseCdp\n} from '../routeTools'\n\n/**\n * 注册受控脚本执行工具。\n *\n * Evaluate 是高风险能力,先单独成组可以让后续默认关闭和权限提示逻辑更容易审查。\n */\nexport function registerEvaluateTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.evaluateScript,\n {\n description:\n 'Evaluate a script in the selected page when explicitly enabled.',\n inputSchema: {\n pageId: z.string().optional(),\n expression: z.string(),\n awaitPromise: z.boolean().optional()\n }\n },\n async (input) => {\n try {\n assertEvaluateEnabled(ctx.options)\n } catch (error) {\n return createToolError(\n error instanceof Error ? error.message : String(error)\n )\n }\n\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (\n cdp &&\n shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n ) {\n try {\n const value = await cdpEvaluate({\n client: cdp.client,\n expression: input.expression,\n awaitPromise: input.awaitPromise\n })\n\n return createToolResponse({ source: 'cdp', value })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.evaluateScript({\n event,\n expression: input.expression,\n awaitPromise: input.awaitPromise,\n timeoutMs: ctx.options.runtime.evaluate.timeoutMs\n })\n })\n\n return createToolResponse({ source: 'hook', result })\n }\n )\n}\n\n/**\n * 校验控制台执行是否已启用。\n *\n * evaluate_script 可以读取和修改页面状态,必须默认拒绝,避免 MCP 客户端无意中获得任意脚本执行能力。\n */\nexport function assertEvaluateEnabled(\n options: ResolvedVueMcpNextOptions\n): void {\n if (!options.runtime.evaluate.enabled) {\n throw new Error(\n 'evaluate_script is disabled. Enable runtime.evaluate.enabled to use it.'\n )\n }\n}\n","import type CDP from 'chrome-remote-interface'\n\n/**\n * CDP 脚本执行参数。\n *\n * 通过 CDP Runtime.evaluate 执行脚本更接近浏览器 DevTools Console 行为。\n */\nexport interface CdpEvaluateOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 要执行的表达式。 */\n readonly expression: string\n /** 是否等待 Promise 结果,适合调试异步页面状态。 */\n readonly awaitPromise?: boolean\n}\n\n/**\n * 使用 CDP 执行控制台表达式。\n *\n * 该能力只在用户显式开启 evaluate_script 后可用,避免默认暴露高风险操作。\n */\nexport async function cdpEvaluate(\n options: CdpEvaluateOptions\n): Promise<unknown> {\n const result = await options.client.Runtime.evaluate({\n expression: options.expression,\n awaitPromise: options.awaitPromise ?? true,\n returnByValue: true\n })\n\n if (result.exceptionDetails) {\n throw new Error(result.exceptionDetails.text || 'CDP evaluate failed')\n }\n\n return result.result.value\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolError, createToolResponse } from '../routeTools'\n\n/**\n * 注册 Network 相关 MCP 工具。\n *\n * 网络调试需要摘要、详情和清理三个入口,提前分组可以让后续 CDP/Hook 双通道实现只替换本文件。\n */\nexport function registerNetworkTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getNetworkRequests,\n {\n description: 'Get captured network request summaries.',\n inputSchema: {\n pageId: z.string().optional(),\n urlContains: z.string().optional(),\n method: z.string().optional(),\n status: z.number().optional(),\n limit: z.number().optional()\n }\n },\n (input) => {\n if (ctx.options.network.mode === 'off') {\n return createToolError(\n 'Network collection is disabled by configuration'\n )\n }\n\n const records = ctx.networkRecords\n .all()\n .filter((record) => !input.pageId || record.pageId === input.pageId)\n .filter(\n (record) =>\n !input.urlContains || record.url.includes(input.urlContains)\n )\n .filter(\n (record) =>\n !input.method ||\n record.method.toUpperCase() === input.method.toUpperCase()\n )\n .filter(\n (record) =>\n input.status === undefined || record.status === input.status\n )\n .slice(-(input.limit ?? ctx.options.network.maxRecords))\n\n return createToolResponse({ requests: records })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getNetworkRequestDetail,\n {\n description: 'Get captured network request detail by id.',\n inputSchema: { id: z.string() }\n },\n (input) => {\n if (ctx.options.network.mode === 'off') {\n return createToolError(\n 'Network collection is disabled by configuration'\n )\n }\n\n const record = ctx.networkRecords\n .all()\n .find((item) => item.id === input.id)\n\n return createToolResponse({ request: record ?? null })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.clearNetworkRequests,\n {\n description: 'Clear cached network requests.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n () => {\n ctx.networkRecords.clear()\n\n return createToolResponse({ ok: true })\n }\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { ViteDevServer } from 'vite'\nimport { normalizePath } from 'vite'\n\n/**\n * Vite 多入口页面描述。\n *\n * MCP 需要告诉 AI 当前项目有哪些可访问页面入口,而不仅仅是已经打开的浏览器页面。\n */\nexport interface VitePageEntry {\n /** Vite root 下的入口文件路径,用于解释页面来源。 */\n readonly file: string\n /** 浏览器访问路径,用于 MCP `list_pages` 输出。 */\n readonly pathname: string\n}\n\n/**\n * 发现 Vite HTML 页面入口。\n *\n * 多页 Vite 项目通常有多个 HTML 文件,该函数用轻量文件扫描补充已连接页面之外的入口列表。\n */\nexport function discoverHtmlEntries(server: ViteDevServer): VitePageEntry[] {\n const root = server.config.root\n const entries: VitePageEntry[] = []\n\n walkHtmlEntries(root, root, entries)\n\n return entries\n}\n\n/**\n * 递归扫描 HTML 入口。\n *\n * 扫描逻辑单独拆分,是为了让入口发现保持简单,同时避免主函数承担目录遍历细节。\n */\nfunction walkHtmlEntries(\n root: string,\n dir: string,\n entries: VitePageEntry[]\n): void {\n for (const item of fs.readdirSync(dir, { withFileTypes: true })) {\n if (item.name === 'node_modules' || item.name.startsWith('.')) {\n continue\n }\n\n const fullPath = path.join(dir, item.name)\n\n if (item.isDirectory()) {\n walkHtmlEntries(root, fullPath, entries)\n continue\n }\n\n if (!item.isFile() || !item.name.endsWith('.html')) {\n continue\n }\n\n const relative = normalizePath(path.relative(root, fullPath))\n entries.push({\n file: relative,\n pathname: relative === 'index.html' ? '/' : `/${relative}`\n })\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ViteDevServer } from 'vite'\nimport { createCdpClient } from '../../cdp/cdpClient'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { discoverHtmlEntries } from '../../plugin/entryDiscovery'\nimport type { PageTarget, VueMcpNextContext } from '../../types'\nimport { createToolResponse } from '../routeTools'\n\n/**\n * 注册页面目标相关 MCP 工具。\n *\n * 页面目标是所有调试工具的入口,先提供 list 能力可以让 AI 明确后续操作作用在哪个页面。\n */\nexport function registerPageTools(\n server: McpServer,\n ctx: VueMcpNextContext,\n vite: ViteDevServer\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.listPages,\n {\n description: 'List Vite page entries and connected runtime/CDP targets.'\n },\n async () => {\n const cdpResult = await listCdpPageTargets(ctx)\n\n for (const target of cdpResult.pages) {\n ctx.pages.upsert(target)\n void ctx.cdpLifecycle?.connectPage(target)\n }\n\n return createToolResponse({\n entries: discoverHtmlEntries(vite),\n pages: ctx.pages.list(),\n cdpError: cdpResult.error\n })\n }\n )\n}\n\n/**\n * 查询 CDP 暴露的页面 target。\n *\n * `list_pages` 是用户选择调试目标的入口,因此即使页面还没有 runtime bridge 连接,\n * 也应该展示 CDP 侧可见 target,方便纯 CDP 调试场景使用。\n */\nasync function listCdpPageTargets(ctx: VueMcpNextContext): Promise<{\n readonly pages: PageTarget[]\n readonly error?: string\n}> {\n if (ctx.options.cdp.wsEndpoint) {\n return { pages: [createWsEndpointTarget(ctx.options.cdp.wsEndpoint)] }\n }\n\n if (!ctx.options.cdp.browserUrl) {\n return { pages: [] }\n }\n\n try {\n const targets = await createCdpClient(ctx.options.cdp).listTargets()\n\n return {\n pages: targets\n .filter((target) => target.type === 'page')\n .map((target) => ({\n pageId: `cdp:${target.id}`,\n source: 'cdp',\n url: target.url,\n pathname: getPathname(target.url),\n title: target.title,\n connected: Boolean(target.webSocketDebuggerUrl)\n }))\n }\n } catch (error) {\n return {\n pages: [],\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 为直接传入 wsEndpoint 的场景创建虚拟页面。\n *\n * 直接 WebSocket endpoint 无法通过 `/json/list` 获取 URL,但仍然是合法 CDP 接入方式,\n * 因此用固定 pageId 暴露给 MCP 客户端,工具调用时会直接连接该 endpoint。\n */\nfunction createWsEndpointTarget(wsEndpoint: string): PageTarget {\n return {\n pageId: 'cdp:ws-endpoint',\n source: 'cdp',\n url: wsEndpoint,\n pathname: 'cdp:ws-endpoint',\n title: 'CDP WebSocket endpoint',\n connected: true\n }\n}\n\n/**\n * 从 URL 中提取 pathname。\n *\n * CDP target 可能包含 `about:blank` 等非标准页面 URL,解析失败时保留原值,\n * 这样 `list_pages` 不会因为浏览器临时页面导致整个工具失败。\n */\nfunction getPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url\n }\n}\n","/**\n * MCP 页面截图工具。\n *\n * 该文件负责在服务端选择 CDP 真截图或 runtime snapdom 降级截图,适用于不同客户端和浏览器调试能力不一致的场景。\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { cdpCaptureScreenshot } from '../../cdp/cdpScreenshot'\nimport type {\n ScreenshotFormat,\n ScreenshotPrefer,\n ScreenshotTarget,\n VueMcpNextContext\n} from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData\n} from '../routeTools'\n\n/** 截图工具默认目标,适合用户不关心整页或局部区域时获取当前视口。 */\nconst DEFAULT_SCREENSHOT_TARGET: ScreenshotTarget = 'viewport'\n\n/** 截图工具默认格式,PNG 对普通 UI 截图更稳定且无损。 */\nconst DEFAULT_SCREENSHOT_FORMAT: ScreenshotFormat = 'png'\n\n/**\n * MCP 截图工具输入 schema。\n *\n * 这里保持和其他工具一致使用 zod 字段对象,方便 MCP SDK 生成参数声明。\n */\nconst screenshotInputSchema = {\n pageId: z.string().optional(),\n target: z.enum(['viewport', 'fullPage', 'element']).optional(),\n selector: z.string().optional(),\n format: z.enum(['png', 'jpeg', 'webp']).optional(),\n prefer: z.enum(['auto', 'cdp', 'runtime']).optional(),\n quality: z.number().optional(),\n scale: z.number().optional(),\n snapdom: z.record(z.string(), z.unknown()).optional()\n}\n\n/**\n * 截图工具输入。\n *\n * MCP SDK 会基于 zod schema 校验入参;内部显式接口让后续 helper 不依赖 SDK 泛型细节。\n */\ninterface ScreenshotToolInput {\n /** 页面目标 ID,适合多 tab 或多入口页面时精确选择截图对象。 */\n readonly pageId?: string\n /** 截图目标范围,默认视口以减少响应体积。 */\n readonly target?: ScreenshotTarget\n /** 元素截图选择器,只在 `target: \"element\"` 时需要。 */\n readonly selector?: string\n /** 图片格式,默认 PNG 以优先保证 UI 清晰度。 */\n readonly format?: ScreenshotFormat\n /** 单次截图通道偏好,适合临时强制验证 runtime 降级效果。 */\n readonly prefer?: ScreenshotPrefer\n /** 有损格式质量,适合临时降低 jpeg/webp 体积。 */\n readonly quality?: number\n /** 单次 snapdom 缩放倍率覆盖值。 */\n readonly scale?: number\n /** 单次 snapdom JSON-safe options 覆盖值。 */\n readonly snapdom?: Record<string, unknown>\n}\n\n/**\n * 注册页面截图 MCP 工具。\n *\n * 截图能力可能返回较大的 base64,因此单独成组可以让体积限制和来源说明集中审查。\n */\nexport function registerScreenshotTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.takeScreenshot,\n {\n description: 'Take a page screenshot using CDP or snapdom fallback.',\n inputSchema: screenshotInputSchema\n },\n async (input) => handleTakeScreenshot(ctx, input as ScreenshotToolInput)\n )\n}\n\n/**\n * 执行截图工具。\n *\n * `auto` 优先 CDP 是为了尽量返回真实浏览器像素;CDP 不可用时才降级到 snapdom 并标记来源。\n */\nasync function handleTakeScreenshot(\n ctx: VueMcpNextContext,\n input: ScreenshotToolInput\n) {\n const target = input.target ?? DEFAULT_SCREENSHOT_TARGET\n const format = input.format ?? DEFAULT_SCREENSHOT_FORMAT\n const prefer = input.prefer ?? ctx.options.screenshot.prefer\n\n if (target === 'element' && !input.selector) {\n return createToolError('selector is required when target is element')\n }\n\n if (prefer !== 'runtime') {\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (cdp) {\n try {\n const screenshot = await cdpCaptureScreenshot({\n client: cdp.client,\n target,\n selector: input.selector,\n format,\n quality: input.quality\n })\n\n return createScreenshotResponse(ctx, {\n source: 'cdp',\n target,\n format,\n data: screenshot.data,\n width: screenshot.width,\n height: screenshot.height,\n mimeType: createMimeType(format),\n byteLength: getBase64ByteLength(screenshot.data)\n })\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n if (prefer === 'cdp') {\n return createToolError('CDP screenshot is unavailable')\n }\n }\n\n return createRuntimeScreenshot(ctx, input, { target, format })\n}\n\n/**\n * 请求浏览器 runtime 执行 snapdom 截图。\n *\n * snapdom 必须在页面上下文运行,服务端只负责传入可序列化配置并校验返回体积。\n */\nasync function createRuntimeScreenshot(\n ctx: VueMcpNextContext,\n input: ScreenshotToolInput,\n normalized: { target: ScreenshotTarget; format: ScreenshotFormat }\n) {\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.takeScreenshot({\n event,\n target: normalized.target,\n selector: input.selector,\n format: normalized.format,\n quality: input.quality,\n scale: input.scale,\n snapdom: {\n ...ctx.options.screenshot.snapdom,\n options: {\n ...ctx.options.screenshot.snapdom.options,\n ...input.snapdom\n }\n }\n })\n })\n\n if (isScreenshotTooLarge(ctx, result)) {\n return createToolError(\n `screenshot is too large: ${String(result.byteLength)} bytes`\n )\n }\n\n if (!isPlainRecord(result)) {\n return createToolError('runtime screenshot returned an invalid response')\n }\n\n return createToolResponse(result)\n}\n\n/**\n * 创建截图响应。\n *\n * CDP 和 runtime 都必须经过同一个体积限制,避免某条通道绕过 MCP 响应保护。\n */\nfunction createScreenshotResponse(\n ctx: VueMcpNextContext,\n result: ScreenshotToolResult\n) {\n if (result.byteLength > ctx.options.screenshot.maxBytes) {\n return createToolError(\n `screenshot is too large: ${String(result.byteLength)} bytes`\n )\n }\n\n return createToolResponse(result)\n}\n\n/**\n * 判断 runtime 截图是否超过体积限制。\n *\n * runtime 回传是 unknown,必须先做结构检查再读取 byteLength。\n */\nfunction isScreenshotTooLarge(\n ctx: VueMcpNextContext,\n result: unknown\n): result is { byteLength: number } {\n return (\n isPlainRecord(result) &&\n 'byteLength' in result &&\n typeof result.byteLength === 'number' &&\n result.byteLength > ctx.options.screenshot.maxBytes\n )\n}\n\n/**\n * 校验结构化响应对象。\n *\n * MCP structuredContent 必须是对象;runtime 回传来自浏览器边界,不能直接信任 unknown。\n */\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * 生成图片 mime type。\n *\n * 服务端 CDP 响应不含 data URL 前缀,显式 mime type 可以让 MCP 客户端正确解码。\n */\nfunction createMimeType(format: ScreenshotFormat): string {\n return `image/${format}`\n}\n\n/**\n * 计算 base64 原始字节数。\n *\n * CDP 返回的是不带 data URL 前缀的 base64,按 padding 修正可以更准确执行 maxBytes 限制。\n */\nfunction getBase64ByteLength(data: string): number {\n const padding = data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0\n return Math.ceil((data.length * 3) / 4) - padding\n}\n\n/**\n * 截图工具统一结果。\n *\n * 该结构让 CDP 真截图和 runtime 降级截图在 MCP 客户端中具备相同的基本字段。\n */\ninterface ScreenshotToolResult {\n /** 允许作为 MCP structuredContent 返回,适配 SDK 对结构化对象的索引签名要求。 */\n readonly [key: string]: unknown\n /** 截图来源,适合解释准确度和限制。 */\n readonly source: 'cdp' | 'snapdom'\n /** 截图范围,帮助用户理解返回图片覆盖的是视口、整页还是元素。 */\n readonly target: ScreenshotTarget\n /** 图片格式,适合客户端解码和保存。 */\n readonly format: ScreenshotFormat\n /** 图片 base64 数据,不包含 data URL 前缀。 */\n readonly data: string\n /** 图片宽度,适合客户端展示和诊断截图范围。 */\n readonly width: number\n /** 图片高度,适合客户端展示和诊断截图范围。 */\n readonly height: number\n /** 图片 mime type,适合 MCP 客户端正确解码。 */\n readonly mimeType: string\n /** 原始字节数,用于体积限制和错误提示。 */\n readonly byteLength: number\n}\n","/**\n * CDP 页面截图能力。\n *\n * 该文件只封装浏览器真实截图路径,适用于用户已经提供 CDP endpoint 的开发场景;\n * runtime 的 snapdom 降级截图放在浏览器端模块里,避免两种准确度不同的实现混在一起。\n */\nimport type CDP from 'chrome-remote-interface'\nimport type { ScreenshotFormat, ScreenshotTarget } from '../types'\n\n/**\n * CDP 截图参数。\n *\n * CDP 截图需要直接操作浏览器调试协议,因此这里要求调用方传入已连接 client,\n * 让连接生命周期仍由 MCP 工具层统一管理。\n */\nexport interface CdpCaptureScreenshotOptions {\n /** 已连接的 CDP client,适用于按次调用后立即关闭的工具执行模式。 */\n readonly client: CDP.Client\n /** 截图目标范围,用于在视口、整页和元素 clip 之间选择不同坐标来源。 */\n readonly target: ScreenshotTarget\n /** 输出格式会影响浏览器截图编码和 MCP 响应体积。 */\n readonly format: ScreenshotFormat\n /** 有损格式质量,适用于 jpeg/webp 降低响应体积的场景。 */\n readonly quality?: number\n /** 元素截图选择器,只在 `target: \"element\"` 时使用。 */\n readonly selector?: string\n}\n\n/**\n * CDP 截图结果。\n *\n * MCP 工具层需要统一计算体积和响应结构,因此 helper 只返回原始 base64 与尺寸。\n */\nexport interface CdpScreenshotResult {\n /** 浏览器返回的 base64 图片数据,不包含 data URL 前缀。 */\n readonly data: string\n /** 截图 CSS 像素宽度,用于让客户端理解图片尺寸。 */\n readonly width: number\n /** 截图 CSS 像素高度,用于让客户端理解图片尺寸。 */\n readonly height: number\n}\n\n/**\n * 使用 CDP 捕获真实浏览器截图。\n *\n * CDP 是最高准确度路径,适合需要覆盖 canvas、video、复杂 CSS 和真实浏览器渲染像素的场景。\n */\nexport async function cdpCaptureScreenshot(\n options: CdpCaptureScreenshotOptions\n): Promise<CdpScreenshotResult> {\n if (options.target === 'element') {\n return captureElementScreenshot(options)\n }\n\n if (options.target === 'fullPage') {\n return captureFullPageScreenshot(options)\n }\n\n return captureViewportScreenshot(options)\n}\n\n/**\n * 捕获当前视口截图。\n *\n * 视口截图不改变页面滚动和尺寸,适合快速获取用户当前正在看的页面状态。\n */\nasync function captureViewportScreenshot(\n options: CdpCaptureScreenshotOptions\n): Promise<CdpScreenshotResult> {\n const metrics = await options.client.Page.getLayoutMetrics()\n const width = Math.ceil(metrics.cssLayoutViewport.clientWidth)\n const height = Math.ceil(metrics.cssLayoutViewport.clientHeight)\n const result = await options.client.Page.captureScreenshot(\n omitUndefined({\n format: options.format,\n quality: createQuality(options),\n captureBeyondViewport: false\n })\n )\n\n return { data: result.data, width, height }\n}\n\n/**\n * 捕获整页截图。\n *\n * 整页截图需要使用内容尺寸作为 clip,否则长页面只会返回当前视口。\n */\nasync function captureFullPageScreenshot(\n options: CdpCaptureScreenshotOptions\n): Promise<CdpScreenshotResult> {\n const metrics = await options.client.Page.getLayoutMetrics()\n const width = Math.ceil(metrics.cssContentSize.width)\n const height = Math.ceil(metrics.cssContentSize.height)\n const result = await options.client.Page.captureScreenshot(\n omitUndefined({\n format: options.format,\n quality: createQuality(options),\n captureBeyondViewport: true,\n clip: { x: 0, y: 0, width, height, scale: 1 }\n })\n )\n\n return { data: result.data, width, height }\n}\n\n/**\n * 捕获指定元素截图。\n *\n * 元素 clip 通过页面运行时计算真实布局位置,适合 Vue 组件或局部区域调试。\n */\nasync function captureElementScreenshot(\n options: CdpCaptureScreenshotOptions\n): Promise<CdpScreenshotResult> {\n if (!options.selector) {\n throw new Error('selector is required when target is element')\n }\n\n const rect = await getElementRect(options.client, options.selector)\n const result = await options.client.Page.captureScreenshot(\n omitUndefined({\n format: options.format,\n quality: createQuality(options),\n captureBeyondViewport: true,\n clip: {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n scale: 1\n }\n })\n )\n\n return { data: result.data, width: rect.width, height: rect.height }\n}\n\n/**\n * 读取元素页面坐标。\n *\n * CDP DOM box model 在不同页面状态下需要 nodeId 绑定;这里使用页面表达式可以更直接匹配用户传入的 selector。\n */\nasync function getElementRect(\n client: CDP.Client,\n selector: string\n): Promise<CdpElementRect> {\n const result = await client.Runtime.evaluate({\n expression: createElementRectExpression(selector),\n awaitPromise: true,\n returnByValue: true\n })\n\n if (result.exceptionDetails) {\n throw new Error(result.exceptionDetails.text || 'element query failed')\n }\n\n const value = result.result.value as unknown\n\n if (!isElementRect(value)) {\n throw new Error(`element not found: ${selector}`)\n }\n\n return value\n}\n\n/**\n * 生成元素坐标表达式。\n *\n * selector 必须使用 JSON.stringify 注入,避免 CSS 选择器中的引号破坏执行脚本。\n */\nfunction createElementRectExpression(selector: string): string {\n return `(() => {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) return null;\n const rect = el.getBoundingClientRect();\n return {\n x: rect.x + window.scrollX,\n y: rect.y + window.scrollY,\n width: rect.width,\n height: rect.height\n };\n})()`\n}\n\n/**\n * 生成有损格式质量参数。\n *\n * PNG 没有质量参数;省略 undefined 可以让测试和协议请求都保持干净。\n */\nfunction createQuality(\n options: CdpCaptureScreenshotOptions\n): number | undefined {\n return options.format === 'png' ? undefined : options.quality\n}\n\n/**\n * 删除 undefined 字段。\n *\n * CDP 请求对象会进入测试断言和协议层,移除空值可以避免把无意义字段传给浏览器。\n */\nfunction omitUndefined<T extends Record<string, unknown>>(value: T): T {\n return Object.fromEntries(\n Object.entries(value).filter(([, item]) => item !== undefined)\n ) as T\n}\n\n/**\n * 元素截图坐标。\n *\n * CDP clip 使用 CSS 像素坐标,因此只保留浏览器截图所需的四个数值字段。\n */\ninterface CdpElementRect {\n /** 页面 X 坐标,包含滚动偏移,适合传给 CDP clip。 */\n readonly x: number\n /** 页面 Y 坐标,包含滚动偏移,适合传给 CDP clip。 */\n readonly y: number\n /** 元素宽度,适合限定局部截图范围。 */\n readonly width: number\n /** 元素高度,适合限定局部截图范围。 */\n readonly height: number\n}\n\n/**\n * 校验元素坐标结构。\n *\n * CDP evaluate 返回 unknown,必须在协议边界显式校验,避免错误值传入截图 clip。\n */\nfunction isElementRect(value: unknown): value is CdpElementRect {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const rect = value as Partial<CdpElementRect>\n\n return (\n typeof rect.x === 'number' &&\n typeof rect.y === 'number' &&\n typeof rect.width === 'number' &&\n rect.width > 0 &&\n typeof rect.height === 'number' &&\n rect.height > 0\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport { nanoid } from 'nanoid'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type { VueMcpNextContext } from '../../types'\nimport { createToolError, createToolResponse } from '../routeTools'\n\n/**\n * 注册 Vue 专属 MCP 工具。\n *\n * Vue 组件、Router 和 Pinia 使用 Runtime Bridge,不走 CDP;独立分组能防止通用 DevTools 路由误用到 Vue 语义。\n */\nexport function registerVueTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getComponentTree,\n { description: 'Get Vue component tree.' },\n async () =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getInspectorTree({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getComponentState,\n {\n description: 'Get Vue component state.',\n inputSchema: { componentName: z.string() }\n },\n async ({ componentName }) =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getInspectorState({ event, componentName })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.editComponentState,\n {\n description: 'Edit Vue component state.',\n inputSchema: {\n componentName: z.string(),\n path: z.array(z.string()),\n value: z.string(),\n valueType: z.enum(['string', 'number', 'boolean', 'object', 'array'])\n }\n },\n ({ componentName, path, value, valueType }) => {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n void ctx.rpcServer.editComponentState({\n componentName,\n path,\n value,\n valueType\n })\n return createToolResponse({ ok: true })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.highlightComponent,\n {\n description: 'Highlight a Vue component.',\n inputSchema: { componentName: z.string() }\n },\n ({ componentName }) => {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n void ctx.rpcServer.highlightComponent({ componentName })\n return createToolResponse({ ok: true })\n }\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getRouterInfo,\n { description: 'Get Vue Router information.' },\n async () =>\n requestVueData(ctx, (event) => {\n ctx.rpcServer?.getRouterInfo({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPiniaTree,\n { description: 'Get Pinia inspector tree.' },\n async () =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getPiniaTree({ event })\n })\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPiniaState,\n {\n description: 'Get Pinia store state.',\n inputSchema: { storeName: z.string() }\n },\n async ({ storeName }) =>\n requestVueData(ctx, (event) => {\n void ctx.rpcServer?.getPiniaState({ event, storeName })\n })\n )\n}\n\n/**\n * 请求 Vue Runtime Bridge 数据并等待回调。\n *\n * Vue 工具依赖浏览器页面在线,使用超时可以避免 MCP 客户端在页面未打开时永久等待。\n */\nasync function requestVueData(\n ctx: VueMcpNextContext,\n trigger: (event: string) => void\n): Promise<CallToolResult> {\n if (!ctx.rpcServer) {\n return vueBridgeUnavailable()\n }\n\n const event = nanoid()\n const data = await waitForVueHook(ctx, event, () => {\n trigger(event)\n })\n\n return {\n ...createToolResponse({ data })\n }\n}\n\n/**\n * 等待一次 Vue RPC 回调。\n *\n * 使用 hookOnce 保证同一个 event 只唤醒一个 MCP 请求,避免并发请求互相消费结果。\n */\nfunction waitForVueHook(\n ctx: VueMcpNextContext,\n event: string,\n trigger: () => void\n): Promise<unknown> {\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n resolve({ ok: false, error: 'Vue runtime bridge response timed out' })\n }, 5000)\n\n ctx.hooks.hookOnce(event, (data) => {\n clearTimeout(timeout)\n resolve(data)\n })\n trigger()\n })\n}\n\n/**\n * 返回 Vue bridge 不可用错误。\n *\n * 页面未打开或 runtime 尚未连接时,明确错误比空结果更容易让 AI 指导用户修复环境。\n */\nfunction vueBridgeUnavailable(): CallToolResult {\n return createToolError('Vue runtime bridge is not connected')\n}\n","/* eslint-disable @typescript-eslint/no-deprecated -- 当前需要兼容仍使用 /sse 与 /messages 的 MCP 客户端,同时提供 /mcp 给只支持 Streamable HTTP 的客户端。 */\nimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport type { ViteDevServer } from 'vite'\n\n/**\n * 在 Vite dev server 上挂载 MCP 路由。\n *\n * 当前同时保留 SSE 和 Streamable HTTP,是因为不同 MCP 客户端的传输支持不一致;\n * 每次连接都创建独立 McpServer,可以避免一个 server 实例被多个 transport 复用导致状态互相影响。\n */\nexport function setupMcpTransport(\n base: string,\n createServer: () => McpServer,\n vite: ViteDevServer\n): void {\n const transports = new Map<\n string,\n { server: McpServer; transport: SSEServerTransport }\n >()\n\n vite.middlewares.use(`${base}/sse`, (_req, res) => {\n const transport = new SSEServerTransport(`${base}/messages`, res)\n const server = createServer()\n transports.set(transport.sessionId, { server, transport })\n res.on('close', () => {\n transports.delete(transport.sessionId)\n void server.close()\n })\n void server.connect(transport).catch((error: unknown) => {\n res.destroy(error instanceof Error ? error : new Error(String(error)))\n })\n })\n\n vite.middlewares.use(`${base}/mcp`, (req, res) => {\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.end('Method Not Allowed')\n return\n }\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined\n })\n const server = createServer()\n res.on('close', () => {\n void transport.close()\n void server.close()\n })\n\n void server\n .connect(transport)\n .then(() => transport.handleRequest(req, res))\n .catch((error: unknown) => {\n res.destroy(error instanceof Error ? error : new Error(String(error)))\n })\n })\n\n vite.middlewares.use(`${base}/messages`, (req, res) => {\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.end('Method Not Allowed')\n return\n }\n\n const query = new URLSearchParams(req.url?.split('?').pop() || '')\n const sessionId = query.get('sessionId')\n\n if (!sessionId) {\n res.statusCode = 400\n res.end('Bad Request')\n return\n }\n\n const entry = transports.get(sessionId)\n\n if (!entry) {\n res.statusCode = 404\n res.end('Not Found')\n return\n }\n\n void entry.transport.handlePostMessage(req, res).catch((error: unknown) => {\n res.destroy(error instanceof Error ? error : new Error(String(error)))\n })\n })\n}\n","import type { VueMcpNextContext, VueRuntimeRpc } from '../types'\n\n/**\n * 创建服务端 Vue RPC 回调对象。\n *\n * 浏览器端会调用 `on*Updated` 把 Vue DevTools 数据送回服务端,服务端再用 hook event\n * 唤醒对应 MCP 工具请求;这种事件名隔离可以避免并发请求互相串数据。\n */\nexport function createServerVueRuntimeRpc(\n ctx: VueMcpNextContext\n): VueRuntimeRpc {\n return {\n getDomTree: () => undefined,\n onDomTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n queryDom: () => undefined,\n onDomQueryUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n evaluateScript: () => undefined,\n onEvaluateScriptUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n takeScreenshot: () => undefined,\n onScreenshotTaken: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getInspectorTree: () => undefined,\n onInspectorTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getInspectorState: () => undefined,\n onInspectorStateUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n editComponentState: () => undefined,\n highlightComponent: () => undefined,\n getRouterInfo: () => undefined,\n onRouterInfoUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getPiniaTree: () => undefined,\n onPiniaTreeUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n getPiniaState: () => undefined,\n onPiniaInfoUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n }\n }\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { safeStringify } from '../shared/serialization'\nimport type { ConsoleRecord } from '../types'\n\n/**\n * CDP Console 监听参数。\n *\n * Console 事件来自浏览器 Runtime 层,比页面 Hook 更接近 DevTools Console。\n */\nexport interface CdpConsoleOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 页面 ID,用于和 runtime target 合并展示。 */\n readonly pageId: string\n /** 写入日志缓存的回调。 */\n readonly push: (record: ConsoleRecord) => void\n}\n\n/**\n * 启动 CDP Console 监听。\n *\n * 配置 CDP 后,日志能力优先使用该通道;Hook 仍保留早期日志和兜底能力。\n */\nexport async function startCdpConsole(\n options: CdpConsoleOptions\n): Promise<void> {\n await options.client.Runtime.enable()\n options.client.Runtime.consoleAPICalled((event) => {\n options.push({\n id: nanoid(),\n pageId: options.pageId,\n source: 'cdp',\n level: normalizeConsoleLevel(event.type),\n message: event.args\n .map((arg) => safeStringify(arg.value ?? arg.description))\n .join(' '),\n timestamp: event.timestamp\n })\n })\n}\n\n/**\n * 归一化 CDP 日志级别。\n *\n * CDP 使用 warning 等类型名,MCP 工具输出需要和浏览器 console 常见级别保持一致。\n */\nfunction normalizeConsoleLevel(level: string): ConsoleRecord['level'] {\n if (level === 'warning') {\n return 'warn'\n }\n\n if (level === 'error' || level === 'debug' || level === 'info') {\n return level\n }\n\n return 'log'\n}\n","/**\n * 将未知值转换为适合 MCP 文本输出的字符串。\n *\n * Console 参数、脚本执行结果和 Network body 都可能包含循环引用,统一序列化能避免工具调用崩溃。\n */\nexport function safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value\n }\n\n const seen = new WeakSet()\n\n const serialized = JSON.stringify(\n value,\n (_key: string, current: unknown): unknown => {\n if (typeof current !== 'object' || current === null) {\n return current\n }\n\n if (seen.has(current)) {\n return '[Circular]'\n }\n\n seen.add(current)\n return current\n }\n )\n\n return serialized\n}\n","import type CDP from 'chrome-remote-interface'\nimport { nanoid } from 'nanoid'\nimport { maskHeaders } from '../shared/sanitize'\nimport { parseRequestQuery } from '../shared/url'\nimport type { NetworkRecord } from '../types'\n\n/**\n * CDP Network 监听参数。\n *\n * CDP 能看到比 fetch/XHR Hook 更完整的请求生命周期,因此配置可用时优先使用该通道。\n */\nexport interface CdpNetworkOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 页面 ID,用于和 runtime target 合并展示。 */\n readonly pageId: string\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 是否采集响应体,响应体读取可能失败,不能影响请求记录。 */\n readonly captureResponseBody: boolean\n /** 写入网络缓存的回调。 */\n readonly push: (record: NetworkRecord) => void\n}\n\n/**\n * 启动 CDP Network 监听。\n *\n * 记录按 requestId 暂存,等 loadingFinished 或 loadingFailed 后再推送最终记录,\n * 这样可以把请求、响应和错误信息合并成一个 NetworkRecord。\n */\nexport async function startCdpNetwork(\n options: CdpNetworkOptions\n): Promise<void> {\n const records = new Map<string, NetworkRecord>()\n\n await options.client.Network.enable()\n options.client.Network.requestWillBeSent((event) => {\n records.set(event.requestId, {\n id: nanoid(),\n pageId: options.pageId,\n source: 'cdp',\n url: event.request.url,\n method: event.request.method,\n requestHeaders: maskHeaders(\n normalizeHeaders(event.request.headers),\n options.maskHeaders\n ),\n requestQuery: parseRequestQuery(event.request.url),\n requestBody: event.request.postData,\n startedAt: event.timestamp * 1000\n })\n })\n options.client.Network.responseReceived((event) => {\n const record = records.get(event.requestId)\n\n if (!record) {\n return\n }\n\n records.set(event.requestId, {\n ...record,\n status: event.response.status,\n responseHeaders: normalizeHeaders(event.response.headers)\n })\n })\n options.client.Network.loadingFinished((event) => {\n void finalizeCdpNetworkRecord(\n options,\n records,\n event.requestId,\n event.timestamp * 1000\n )\n })\n options.client.Network.loadingFailed((event) => {\n const record = records.get(event.requestId)\n\n if (!record) {\n return\n }\n\n records.delete(event.requestId)\n options.push({\n ...record,\n error: event.errorText,\n endedAt: event.timestamp * 1000,\n durationMs: event.timestamp * 1000 - record.startedAt\n })\n })\n}\n\n/**\n * 完成 CDP 网络记录。\n *\n * response body 可能因为跨域、缓存或 DevTools 限制读取失败,失败时只省略 body,不中断记录推送。\n */\nasync function finalizeCdpNetworkRecord(\n options: CdpNetworkOptions,\n records: Map<string, NetworkRecord>,\n requestId: string,\n endedAt: number\n): Promise<void> {\n const record = records.get(requestId)\n\n if (!record) {\n return\n }\n\n records.delete(requestId)\n options.push({\n ...record,\n responseBody: options.captureResponseBody\n ? await safeGetResponseBody(options.client, requestId)\n : undefined,\n endedAt,\n durationMs: endedAt - record.startedAt\n })\n}\n\n/**\n * 安全读取 CDP 响应体。\n *\n * CDP 的 getResponseBody 在部分请求上会失败,调试工具不能因为单个 body 失败丢掉整条请求。\n */\nasync function safeGetResponseBody(\n client: CDP.Client,\n requestId: string\n): Promise<string | undefined> {\n try {\n return (await client.Network.getResponseBody({ requestId })).body\n } catch {\n return undefined\n }\n}\n\n/**\n * 归一化 CDP headers。\n *\n * CDP header value 可能不是字符串,统一转字符串可以保持 NetworkRecord 可序列化。\n */\nfunction normalizeHeaders(\n headers: Record<string, unknown>\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).map(([key, value]) => [key, String(value)])\n )\n}\n","/**\n * 文本截断结果。\n *\n * MCP 输出需要明确告诉调用方内容被截断,否则 AI 可能误以为看到的是完整响应。\n */\nexport interface TruncatedText {\n /** 截断后的文本。 */\n readonly text: string\n /** 是否发生截断。 */\n readonly truncated: boolean\n /** 原始文本长度,用于判断丢失信息规模。 */\n readonly originalLength: number\n}\n\n/**\n * 截断长文本。\n *\n * DOM 文本和响应体都可能很大,统一截断策略可以避免不同工具输出行为不一致。\n */\nexport function truncateText(text: string, maxLength: number): TruncatedText {\n if (text.length <= maxLength) {\n return { text, truncated: false, originalLength: text.length }\n }\n\n return {\n text: text.slice(0, maxLength),\n truncated: true,\n originalLength: text.length\n }\n}\n\n/**\n * 对敏感 header 做脱敏。\n *\n * Network 调试需要展示 header,但认证和 Cookie 不应原样暴露给 AI 客户端。\n */\nexport function maskHeaders(\n headers: Record<string, string> = {},\n maskNames: readonly string[] = []\n): Record<string, string> {\n const normalizedMaskNames = new Set(\n maskNames.map((name) => name.toLowerCase())\n )\n\n return Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n normalizedMaskNames.has(name.toLowerCase()) ? '[masked]' : value\n ])\n )\n}\n","/**\n * 解析请求 URL 中的 query 参数。\n *\n * Network 工具需要直接回答“请求参数是什么”,将 query 拆成结构化对象可以减少 AI 重复解析。\n */\nexport function parseRequestQuery(\n url: string\n): Record<string, string | string[]> {\n const parsed = new URL(url, 'http://vite-plugin-vue-mcp-next.local')\n const queryEntries = new Map<string, string | string[]>()\n\n for (const [key, value] of parsed.searchParams.entries()) {\n const existing = queryEntries.get(key)\n\n if (existing === undefined) {\n queryEntries.set(key, value)\n continue\n }\n\n if (Array.isArray(existing)) {\n existing.push(value)\n continue\n }\n\n queryEntries.set(key, [existing, value])\n }\n\n return Object.fromEntries(queryEntries)\n}\n\n/**\n * 获取 URL pathname。\n *\n * 页面 target 可能上报绝对 URL 或相对路径,该 helper 让展示逻辑不需要关心来源格式。\n */\nexport function safeUrlPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url.split('?')[0] || '/'\n }\n}\n","import type CDP from 'chrome-remote-interface'\nimport { startCdpConsole } from '../cdp/cdpConsole'\nimport { createCdpClient } from '../cdp/cdpClient'\nimport { startCdpNetwork } from '../cdp/cdpNetwork'\nimport { matchCdpTarget } from '../cdp/targetMatcher'\nimport { shouldUseCdp } from '../mcp/routeTools'\nimport type {\n CdpLifecycleController,\n PageTarget,\n VueMcpNextContext\n} from '../types'\n\n/**\n * 创建 CDP 生命周期控制器。\n *\n * 该控制器只在用户配置 CDP 时工作;未配置时保持空操作,让 Hook 通道继续承担默认采集。\n */\nexport function createCdpLifecycleController(\n ctx: VueMcpNextContext\n): CdpLifecycleController {\n const clients = new Map<string, CDP.Client>()\n\n return {\n async connectPage(target) {\n if (clients.has(target.pageId) || !shouldStartCdp(ctx)) {\n return\n }\n\n const client = await safeConnectCdp(ctx, target)\n\n if (!client) {\n return\n }\n\n clients.set(target.pageId, client)\n try {\n await startCdpObservers(ctx, target, client)\n } catch (error) {\n clients.delete(target.pageId)\n await client.close()\n warnWhenCdpForced(ctx, error)\n }\n },\n async closeAll() {\n await Promise.all([...clients.values()].map((client) => client.close()))\n clients.clear()\n }\n }\n}\n\n/**\n * 判断是否需要启动 CDP 长连接。\n *\n * 只有 Console 或 Network 至少一个能力需要 CDP 时才建立连接,避免用户只配置 CDP 给 DOM/Evaluate\n * 按需使用时也被动占用浏览器调试连接。\n */\nfunction shouldStartCdp(ctx: VueMcpNextContext): boolean {\n const consoleUsesCdp = shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.runtime.mode,\n hasMatchedCdpTarget: true\n })\n const networkUsesCdp = shouldUseCdp({\n options: ctx.options,\n capabilityMode: ctx.options.network.mode,\n hasMatchedCdpTarget: true\n })\n\n return consoleUsesCdp || networkUsesCdp\n}\n\n/**\n * 安全连接页面对应的 CDP target。\n *\n * `auto` 模式下 CDP 失败应回退到 Hook,不应打断 Vite 启动;`cdp` 模式的工具调用仍会返回明确错误。\n */\nasync function safeConnectCdp(\n ctx: VueMcpNextContext,\n target: PageTarget\n): Promise<CDP.Client | undefined> {\n try {\n return await connectCdp(ctx, target)\n } catch (error) {\n warnWhenCdpForced(ctx, error)\n\n return undefined\n }\n}\n\n/**\n * 只在强制 CDP 模式下输出警告。\n *\n * `auto` 模式的失败是预期回退路径,不应该污染普通开发日志;强制 CDP 则需要提示用户修正端点。\n */\nfunction warnWhenCdpForced(ctx: VueMcpNextContext, error: unknown): void {\n if (ctx.options.runtime.mode !== 'cdp' && ctx.options.network.mode !== 'cdp') {\n return\n }\n\n console.warn(\n `[vite-plugin-vue-mcp-next] CDP connect failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n )\n}\n\n/**\n * 连接指定页面的 CDP target。\n *\n * browserUrl 需要先发现 target 再连接;wsEndpoint 则认为用户已经完成目标选择,直接连接即可。\n */\nasync function connectCdp(\n ctx: VueMcpNextContext,\n target: PageTarget\n): Promise<CDP.Client | undefined> {\n const cdp = createCdpClient(ctx.options.cdp)\n\n if (ctx.options.cdp.wsEndpoint) {\n return cdp.connect(ctx.options.cdp.wsEndpoint)\n }\n\n if (!ctx.options.cdp.browserUrl) {\n return undefined\n }\n\n const matched = matchCdpTarget(await cdp.listTargets(), {\n url: target.url,\n targetUrlPattern: ctx.options.cdp.targetUrlPattern\n })\n\n if (!matched?.webSocketDebuggerUrl) {\n return undefined\n }\n\n return cdp.connect(matched.webSocketDebuggerUrl)\n}\n\n/**\n * 启动需要长连接的 CDP 监听器。\n *\n * DOM 和 Evaluate 是短请求能力,不在这里注册;Console 和 Network 必须持续监听才能捕获事件时间线。\n */\nasync function startCdpObservers(\n ctx: VueMcpNextContext,\n target: PageTarget,\n client: CDP.Client\n): Promise<void> {\n if (ctx.options.runtime.mode !== 'hook') {\n await startCdpConsole({\n client,\n pageId: target.pageId,\n push: (record) => {\n ctx.consoleRecords.push(record)\n }\n })\n }\n\n if (\n ctx.options.network.mode === 'auto' ||\n ctx.options.network.mode === 'cdp'\n ) {\n await startCdpNetwork({\n client,\n pageId: target.pageId,\n maskHeaders: ctx.options.network.maskHeaders,\n captureResponseBody: ctx.options.network.captureResponseBody,\n push: (record) => {\n ctx.networkRecords.push(record)\n }\n })\n }\n}\n","import type { IndexHtmlTransformResult, ResolvedConfig } from 'vite'\nimport {\n RESOLVED_VIRTUAL_RUNTIME_ID,\n RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID,\n VIRTUAL_RUNTIME_ID,\n VIRTUAL_SCREENSHOT_CONFIG_ID\n} from '../constants'\nimport type { SnapdomPluginImport } from '../types'\nimport type { ResolvedVueMcpNextOptions } from '../types'\n\n/**\n * 管理运行时脚本注入。\n *\n * Vite 项目可能使用 HTML 入口,也可能通过框架入口文件启动,\n * 因此注入逻辑必须同时支持 `transformIndexHtml` 和 `appendTo` 两种方式。\n */\nexport interface RuntimeInjectionController {\n /** 解析虚拟模块 ID,使浏览器端可以通过 Vite 加载 runtime client。 */\n resolveId(importee: string): string | undefined\n /** 加载 runtime client 模块内容。 */\n load(id: string): string | undefined\n /** 在 HTML 入口中注入 runtime client。 */\n transformIndexHtml(html: string): IndexHtmlTransformResult | undefined\n /** 在非 HTML 入口中追加 runtime import。 */\n transform(code: string, id: string, ssr?: boolean): string | undefined\n}\n\n/**\n * 创建运行时注入控制器。\n *\n * 将注入行为拆出 Vite 插件主文件,可以让后续测试单独覆盖 HTML 注入和 appendTo 注入。\n */\nexport function createRuntimeInjectionController(\n options: ResolvedVueMcpNextOptions,\n getConfig: () => ResolvedConfig | undefined\n): RuntimeInjectionController {\n return {\n resolveId(importee) {\n if (importee === VIRTUAL_RUNTIME_ID) {\n return RESOLVED_VIRTUAL_RUNTIME_ID\n }\n\n if (importee === VIRTUAL_SCREENSHOT_CONFIG_ID) {\n return RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID\n }\n\n return undefined\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {\n return \"import { startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';\\nvoid startRuntimeClient();\"\n }\n\n if (id === RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID) {\n return createScreenshotConfigModule(options)\n }\n\n return undefined\n },\n transformIndexHtml(html) {\n if (options.appendTo) {\n return undefined\n }\n\n const base = getConfig()?.base || '/'\n\n return {\n html,\n tags: [\n {\n tag: 'script',\n injectTo: 'head-prepend',\n attrs: {\n type: 'module',\n src: `${base}@id/${VIRTUAL_RUNTIME_ID}`\n }\n }\n ]\n }\n },\n transform(code, id, ssr) {\n if (ssr || !options.appendTo) {\n return undefined\n }\n\n const [filename] = id.split('?', 2)\n const matched =\n typeof options.appendTo === 'string'\n ? filename.endsWith(options.appendTo)\n : options.appendTo.test(filename)\n\n if (!matched) {\n return undefined\n }\n\n return `import '${VIRTUAL_RUNTIME_ID}';\\n${code}`\n }\n }\n}\n\n/**\n * 生成 snapdom 扩展虚拟模块。\n *\n * 用户配置的是 Vite import 路径,必须让 Vite 通过静态 import 解析 alias、TS 和插件转换;\n * runtime 再按原始 path 查表,可以避免浏览器原生动态 import 无法理解别名。\n */\nfunction createScreenshotConfigModule(\n options: ResolvedVueMcpNextOptions\n): string {\n const paths = collectScreenshotImportPaths(options)\n const imports = paths\n .map((item, index) => `import * as m${String(index)} from ${JSON.stringify(item)};`)\n .join('\\n')\n const entries = paths\n .map((item, index) => `${JSON.stringify(item)}: m${String(index)}`)\n .join(',\\n ')\n\n return `${imports}\\nexport const screenshotModuleRegistry = {\\n ${entries}\\n};\\n`\n}\n\n/**\n * 收集截图配置中的 Vite import 路径。\n *\n * 插件、filter 和 fallbackURL 都可能引用用户源码模块,去重后生成虚拟模块可以减少重复 import。\n */\nfunction collectScreenshotImportPaths(\n options: ResolvedVueMcpNextOptions\n): string[] {\n const paths = new Set<string>()\n\n for (const plugin of options.screenshot.snapdom.plugins) {\n paths.add(getPluginPath(plugin))\n }\n\n if (options.screenshot.snapdom.filter) {\n paths.add(options.screenshot.snapdom.filter)\n }\n\n if (options.screenshot.snapdom.fallbackURL) {\n paths.add(options.screenshot.snapdom.fallbackURL)\n }\n\n return [...paths]\n}\n\n/**\n * 读取插件路径。\n *\n * 支持字符串和对象两种配置形态,可以让用户在简单默认导出和带参数插件工厂之间选择。\n */\nfunction getPluginPath(plugin: SnapdomPluginImport): string {\n return typeof plugin === 'string' ? plugin : plugin.path\n}\n","import path from 'node:path'\nimport type { ResolvedVueMcpNextOptions } from '../../types'\nimport { updateCodexMcpClientConfig } from './codexConfig'\nimport { updateJsonMcpClientConfig } from './jsonConfig'\n\nexport { updateCodexMcpClientConfig } from './codexConfig'\nexport { updateJsonMcpClientConfig } from './jsonConfig'\n\n/** 多客户端 MCP 写入器只需要 resolved 后的 mcpClients 字段,测试可直接传入该字段。 */\nexport type ResolvedMcpClientConfigOptions =\n ResolvedVueMcpNextOptions['mcpClients']\n\n/**\n * 更新所有启用的项目级 MCP 客户端配置。\n *\n * 自动配置属于开发体验增强;每个客户端独立处理错误,避免某个配置文件损坏时影响 Vite 启动。\n */\nexport async function updateMcpClientConfigs(\n root: string,\n sseUrl: string,\n streamableHttpUrl: string,\n options: ResolvedMcpClientConfigOptions\n): Promise<void> {\n const serverName = options.serverName\n const jobs: Promise<void>[] = []\n\n if (options.cursor) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Cursor',\n configPath: path.join(root, '.cursor', 'mcp.json'),\n mcpUrl: sseUrl,\n serverName\n })\n )\n }\n\n if (options.codex) {\n jobs.push(\n updateCodexMcpClientConfig({\n configPath: path.join(root, '.codex', 'config.toml'),\n mcpUrl: streamableHttpUrl,\n serverName\n })\n )\n }\n\n if (options.claudeCode) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Claude Code',\n configPath: path.join(root, '.mcp.json'),\n mcpUrl: sseUrl,\n serverName\n })\n )\n }\n\n if (options.trae) {\n jobs.push(\n updateJsonMcpClientConfig({\n clientName: 'Trae',\n configPath: path.join(root, '.trae', 'mcp.json'),\n mcpUrl: sseUrl,\n serverName\n })\n )\n }\n\n await Promise.all(jobs)\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/** Codex TOML 写入参数,集中承载可以避免后续扩展 env、headers 时增加位置参数。 */\nexport interface UpdateCodexMcpClientConfigOptions {\n /** 目标 `.codex/config.toml` 文件路径。 */\n readonly configPath: string\n /** 当前 Vite dev server 暴露给 Codex 的 Streamable HTTP 地址。 */\n readonly mcpUrl: string\n /** Codex 中展示的 MCP 服务名,只替换该服务对应 TOML 区块。 */\n readonly serverName: string\n}\n\n/**\n * 写入 Codex 项目级 MCP 配置。\n *\n * 这里不引入 TOML 解析依赖,是因为只需要追加本插件自己的区块;\n * 不覆盖已有同名区块可以保留用户手动配置的端口、路径或兼容性参数。\n */\nexport async function updateCodexMcpClientConfig(\n options: UpdateCodexMcpClientConfigOptions\n): Promise<void> {\n try {\n const current = await readOptionalTextFile(options.configPath)\n const next = replaceOrAppendOwnedBlock(current, options)\n\n await fs.mkdir(path.dirname(options.configPath), { recursive: true })\n await fs.writeFile(options.configPath, next)\n } catch (error) {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to update Codex MCP config at ${options.configPath}: ${formatError(error)}`\n )\n }\n}\n\nfunction replaceOrAppendOwnedBlock(\n current: string,\n options: UpdateCodexMcpClientConfigOptions\n): string {\n const block = createCodexServerBlock(options)\n const matcher = createOwnedBlockMatcher(options.serverName)\n\n if (matcher.test(current)) {\n return ensureTrailingNewline(current)\n }\n\n const separator = current.trim() ? '\\n\\n' : ''\n return `${trimEndNewline(current)}${separator}${block}`\n}\n\nfunction createCodexServerBlock(\n options: UpdateCodexMcpClientConfigOptions\n): string {\n return `${createTableHeader(options.serverName)}\\nurl = ${quoteTomlString(options.mcpUrl)}\\n`\n}\n\nfunction createOwnedBlockMatcher(serverName: string): RegExp {\n const plainHeader = escapeRegExp(`[mcp_servers.${serverName}]`)\n const quotedHeader = escapeRegExp(\n `[mcp_servers.${quoteTomlKey(serverName)}]`\n )\n\n return new RegExp(\n `(?:^|\\\\n)(?:${plainHeader}|${quotedHeader})\\\\n[\\\\s\\\\S]*?(?=\\\\n\\\\[|$)`\n )\n}\n\nfunction createTableHeader(serverName: string): string {\n const key = /^[A-Za-z0-9_-]+$/.test(serverName)\n ? serverName\n : quoteTomlKey(serverName)\n return `[mcp_servers.${key}]`\n}\n\nfunction quoteTomlKey(value: string): string {\n return quoteTomlString(value)\n}\n\nfunction quoteTomlString(value: string): string {\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n}\n\nasync function readOptionalTextFile(filePath: string): Promise<string> {\n try {\n return await fs.readFile(filePath, 'utf-8')\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return ''\n }\n\n throw error\n }\n}\n\nfunction trimEndNewline(value: string): string {\n return value.replace(/\\n+$/u, '')\n}\n\nfunction ensureTrailingNewline(value: string): string {\n return value.endsWith('\\n') ? value : `${value}\\n`\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/** JSON MCP 配置写入参数,用对象承载可以避免客户端差异继续增加时拉长函数参数列表。 */\nexport interface UpdateJsonMcpClientConfigOptions {\n /** 客户端展示名,用于警告日志定位是哪一种配置失败。 */\n readonly clientName: string\n /** 目标配置文件路径,调用方负责传入项目级路径。 */\n readonly configPath: string\n /** 当前 Vite dev server 暴露的 MCP SSE 地址。 */\n readonly mcpUrl: string\n /** 写入 MCP 客户端的服务名,只更新该服务以保护用户已有配置。 */\n readonly serverName: string\n}\n\n/**\n * 写入 JSON 结构的项目级 MCP 配置。\n *\n * Cursor、Claude Code 和 Trae 都使用 `mcpServers` JSON 结构;共用该函数可以确保\n * “保留用户已有配置,只更新本插件条目”的行为在不同客户端中一致。\n */\nexport async function updateJsonMcpClientConfig(\n options: UpdateJsonMcpClientConfigOptions\n): Promise<void> {\n try {\n const config = await readJsonConfig(options.configPath)\n\n if (!isPlainRecord(config)) {\n warnConfigFailure(options, 'config root must be a JSON object')\n return\n }\n\n const mcpServers = isPlainRecord(config.mcpServers)\n ? config.mcpServers\n : {}\n if (Object.hasOwn(mcpServers, options.serverName)) {\n return\n }\n\n mcpServers[options.serverName] = { type: 'sse', url: options.mcpUrl }\n config.mcpServers = mcpServers\n\n await fs.mkdir(path.dirname(options.configPath), { recursive: true })\n await fs.writeFile(\n options.configPath,\n `${JSON.stringify(config, null, 2)}\\n`\n )\n } catch (error) {\n warnConfigFailure(options, formatError(error))\n }\n}\n\nasync function readJsonConfig(configPath: string): Promise<unknown> {\n const raw = await readOptionalTextFile(configPath)\n\n if (!raw.trim()) {\n return {}\n }\n\n return JSON.parse(raw)\n}\n\nasync function readOptionalTextFile(filePath: string): Promise<string> {\n try {\n return await fs.readFile(filePath, 'utf-8')\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return '{}'\n }\n\n throw error\n }\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction warnConfigFailure(\n options: UpdateJsonMcpClientConfigOptions,\n reason: string\n): void {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to update ${options.clientName} MCP config at ${options.configPath}: ${reason}`\n )\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error\n}\n"],"mappings":"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","names":["import_vite","CDP","import_zod","snapshot","nodes","import_zod","import_zod","fs","path","import_zod","import_nanoid","import_zod","path","import_nanoid","import_nanoid","import_node_path","import_node_path","fs","path","import_promises","import_node_path","isPlainRecord","fs","path","formatError","readOptionalTextFile","isNodeError","path"]}