@xiaou66/vite-plugin-vue-mcp-next 1.0.0 → 1.0.2

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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/mcp/tools/pages.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/screenshot.ts","../src/cdp/cdpScreenshot.ts","../src/mcp/tools/screenshotOutput.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":["import type { Plugin, ResolvedConfig } from 'vite'\nimport { searchForWorkspaceRoot } from 'vite'\nimport { mergeOptions, RUNTIME_PAGE_RECONNECTED_EVENT } 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.server = 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 ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, 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 DEFAULT_SCREENSHOT_SAVE_DIR = '.vite-mcp/screenshot'\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n reloadPage: 'reload_page',\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/** snapdom loader 虚拟模块 ID,用于把 optional peer 解析限制在宿主 Vite 模块图里。 */\nexport const VIRTUAL_SNAPDOM_LOADER_ID =\n 'virtual:vite-plugin-vue-mcp-next/snapdom-loader'\n\n/** Vite 内部解析 snapdom loader 时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\\0${VIRTUAL_SNAPDOM_LOADER_ID}`\n\n/** 默认 MCP 客户端服务名,集中定义可以让旧 Cursor 配置和新多客户端配置保持一致。 */\nconst DEFAULT_MCP_CLIENT_SERVER_NAME = 'vue-mcp-next'\n\n/** Runtime 页面重连事件名,供 reload_page 等待页面刷新后重新接入。 */\nexport const RUNTIME_PAGE_RECONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-reconnected'\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 type: 'path',\n saveDir: DEFAULT_SCREENSHOT_SAVE_DIR,\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: 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 type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport type { ViteDevServer } from 'vite'\nimport { createCdpClient } from '../../cdp/cdpClient'\nimport { MCP_TOOL_NAMES, RUNTIME_PAGE_RECONNECTED_EVENT } from '../../constants'\nimport { discoverHtmlEntries } from '../../plugin/entryDiscovery'\nimport type { PageTarget, VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} 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 server.registerTool(\n MCP_TOOL_NAMES.reloadPage,\n {\n description:\n 'Reload the selected page. CDP uses ignoreCache; Runtime Hook falls back to normal reload.',\n inputSchema: {\n pageId: z.string().optional(),\n ignoreCache: z.boolean().optional()\n }\n },\n async (input) => {\n if (hasCdpConfig(ctx)) {\n return reloadPageWithCdp(ctx, input.pageId, input.ignoreCache ?? true)\n }\n\n const target = resolveRuntimeReloadTarget(ctx, input.pageId)\n\n if (!target.ok) {\n return createToolError(target.error)\n }\n\n const reconnect = waitForRuntimePageReconnect(ctx)\n ctx.pages.disconnect(target.page.pageId)\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.reloadPage({ event })\n })\n\n if (!isRecord(result) || result.ok === false) {\n reconnect.cancel()\n\n return createToolResponse(\n isRecord(result)\n ? result\n : { ok: false, error: 'Invalid runtime reload response' }\n )\n }\n\n const page = await reconnect.promise\n\n return createToolResponse(\n page\n ? { ...result, reconnected: true, pageId: page.pageId, page }\n : {\n ...result,\n reconnected: false,\n error: 'runtime page reconnect timed out'\n }\n )\n }\n )\n}\n\n/**\n * 判断是否应进入 CDP 刷新路径。\n *\n * 刷新工具的语义和 DOM/Evaluate 不同:只要用户显式配置了 CDP,就应该使用浏览器协议的\n * `ignoreCache` 能力;未配置时才退回 Runtime Hook 普通刷新。\n */\nfunction hasCdpConfig(ctx: VueMcpNextContext): boolean {\n return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint)\n}\n\n/**\n * 校验 Runtime RPC 回包是否可作为 MCP structuredContent。\n *\n * Runtime 通道来自浏览器页面,服务端需要把未知值收窄为对象,避免 MCP SDK 的结构化响应类型\n * 接收到数组或原始值。\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * 解析 Runtime 刷新的目标页面。\n *\n * Runtime reload 会让旧 bridge 失效,因此刷新前必须先定位并标记旧 pageId,\n * 避免 `list_pages` 在新页面连接后同时保留两个可用目标。\n */\nfunction resolveRuntimeReloadTarget(\n ctx: VueMcpNextContext,\n pageId?: string\n): { ok: true; page: PageTarget } | { ok: false; error: string } {\n try {\n const page = resolvePageTarget(ctx, pageId)\n\n if (page.source !== 'runtime') {\n return {\n ok: false,\n error: 'Runtime reload requires a runtime page target'\n }\n }\n\n return { ok: true, page }\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 等待刷新后的 Runtime 页面重新接入。\n *\n * 该等待只用于确认页面 bridge 已经重新建立;超时返回 null,让调用方可以把“已触发但未确认”\n * 明确暴露给 MCP 客户端,而不是无限挂起。\n */\nfunction waitForRuntimePageReconnect(ctx: VueMcpNextContext): {\n readonly promise: Promise<PageTarget | null>\n cancel(): void\n} {\n let timeout: NodeJS.Timeout | undefined\n let cleanup: (() => void) | undefined\n const promise = new Promise<PageTarget | null>((resolve) => {\n timeout = setTimeout(() => {\n cleanup?.()\n resolve(null)\n }, 5000)\n cleanup = ctx.hooks.hookOnce(RUNTIME_PAGE_RECONNECTED_EVENT, (payload) => {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n resolve(isPageTarget(payload) ? payload : null)\n })\n })\n\n return {\n promise,\n cancel() {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n cleanup?.()\n }\n }\n}\n\n/**\n * 校验页面重连事件载荷。\n *\n * 事件来自浏览器运行时,刷新工具只依赖页面目标最小字段,避免把异常 payload 当成刷新完成。\n */\nfunction isPageTarget(value: unknown): value is PageTarget {\n if (!isRecord(value)) {\n return false\n }\n\n return (\n typeof value.pageId === 'string' &&\n (value.source === 'runtime' || value.source === 'cdp') &&\n typeof value.url === 'string' &&\n typeof value.pathname === 'string' &&\n typeof value.connected === 'boolean'\n )\n}\n\n/**\n * 通过 CDP 执行页面刷新。\n *\n * `ignoreCache` 是 CDP 的标准刷新参数,适合测试前规避浏览器 HTTP 缓存;\n * 连接生命周期仍保持按工具调用即连即关,避免开发服务器长期占用调试连接。\n */\nasync function reloadPageWithCdp(\n ctx: VueMcpNextContext,\n pageId: string | undefined,\n ignoreCache: boolean\n) {\n const cdp = await connectCdpForPage(ctx, pageId)\n\n if (!cdp) {\n return createToolError('CDP target is unavailable for page reload')\n }\n\n try {\n await cdp.client.Page.enable()\n const loaded = cdp.client.Page.loadEventFired()\n await cdp.client.Page.reload({ ignoreCache })\n await loaded\n\n return createToolResponse({\n ok: true,\n source: 'cdp',\n ignoreCache,\n pageId\n })\n } finally {\n await closeCdpClient(cdp.client)\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 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","/**\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'\nimport {\n createScreenshotOutput,\n type ScreenshotImagePayload\n} from './screenshotOutput'\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 await 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 if (result.ok === false) {\n return createToolResponse(result)\n }\n\n if (!isScreenshotImagePayload(result)) {\n return createToolError('runtime screenshot returned an invalid response')\n }\n\n return createScreenshotResponse(ctx, {\n ...result,\n target: normalized.target,\n format: normalized.format\n })\n}\n\n/**\n * 创建截图响应。\n *\n * CDP 和 runtime 都必须经过同一个体积限制,避免某条通道绕过 MCP 响应保护。\n */\nasync function createScreenshotResponse(\n ctx: VueMcpNextContext,\n result: ScreenshotImagePayload\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 try {\n return createToolResponse(await createScreenshotOutput(ctx, result))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n return createToolError(`failed to create screenshot output: ${message}`)\n }\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 * 校验 runtime 成功截图结果。\n *\n * 浏览器 runtime 返回 unknown,服务端必须确认图片字段完整后才能写入文件系统。\n */\nfunction isScreenshotImagePayload(\n result: Record<string, unknown>\n): result is ScreenshotImagePayload {\n return (\n (result.source === 'cdp' || result.source === 'snapdom') &&\n typeof result.data === 'string' &&\n typeof result.width === 'number' &&\n typeof result.height === 'number' &&\n typeof result.mimeType === 'string' &&\n typeof result.byteLength === 'number'\n )\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","/**\n * 服务端截图输出工具。\n *\n * CDP 与浏览器 runtime 都只能稳定产出图片数据,项目路径写入必须在 Vite dev server 侧统一处理。\n */\nimport { randomUUID } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type {\n ResolvedVueMcpNextOptions,\n ScreenshotFormat,\n ScreenshotTarget\n} from '../../types'\n\n/** 截图来源,调用方需要用它解释 CDP 真截图与 snapdom DOM 截图的差异。 */\nexport type ScreenshotOutputSource = 'cdp' | 'snapdom'\n\n/** 截图原始数据,输出 helper 会按项目配置转换为路径或 base64 响应。 */\nexport interface ScreenshotImagePayload {\n readonly [key: string]: unknown\n /** 截图来源,适合调用方判断截图可信度和限制。 */\n readonly source: ScreenshotOutputSource\n /** 截图范围,用于文件名和返回元数据。 */\n readonly target: ScreenshotTarget\n /** 图片格式,用于 mime type 和扩展名保持一致。 */\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,便于客户端解码。 */\n readonly mimeType: string\n /** 原始字节数,用于体积限制和结果说明。 */\n readonly byteLength: number\n /** runtime DOM 截图的已知限制,CDP 截图通常不需要该字段。 */\n readonly limitations?: readonly string[]\n}\n\n/** 路径输出结果,默认用于项目级 MCP,避免 base64 占用模型上下文。 */\nexport interface ScreenshotPathOutput\n extends Omit<ScreenshotImagePayload, 'data'> {\n /** 截图文件绝对路径,适合 MCP 客户端直接读取。 */\n readonly path: string\n /** 相对 Vite 项目根目录路径,适合用户在项目内定位。 */\n readonly relativePath: string\n}\n\n/** 截图输出结果,项目配置决定返回路径还是保留 base64 数据。 */\nexport type ScreenshotOutput = ScreenshotImagePayload | ScreenshotPathOutput\n\n/** 截图输出所需的最小服务端上下文,避免把 helper 绑定到完整 ViteDevServer 实例。 */\nexport interface ScreenshotOutputContext {\n /** 已解析插件配置,输出策略只读取项目级截图配置。 */\n readonly options: ResolvedVueMcpNextOptions\n /** Vite 项目根目录来源,path 模式需要它解析相对 saveDir。 */\n readonly server?: {\n readonly config: {\n readonly root: string\n }\n }\n}\n\n/**\n * 创建截图输出。\n *\n * 该函数集中处理项目级输出策略,让 CDP 和 runtime 通道不关心文件系统细节。\n */\nexport async function createScreenshotOutput(\n ctx: ScreenshotOutputContext,\n payload: ScreenshotImagePayload\n): Promise<ScreenshotOutput> {\n if (ctx.options.screenshot.type === 'base64') {\n return payload\n }\n\n const saveDir = resolveScreenshotSaveDir(ctx)\n await mkdir(saveDir, { recursive: true })\n const filePath = path.join(saveDir, createScreenshotFileName(payload))\n await writeFile(filePath, Buffer.from(payload.data, 'base64'))\n\n return {\n source: payload.source,\n target: payload.target,\n format: payload.format,\n width: payload.width,\n height: payload.height,\n mimeType: payload.mimeType,\n byteLength: payload.byteLength,\n limitations: payload.limitations,\n path: filePath,\n relativePath: createProjectRelativePath(ctx, filePath)\n }\n}\n\n/**\n * 解析截图保存目录。\n *\n * 相对路径必须基于 Vite root,而不是当前 shell 工作目录,否则 monorepo 中会写错项目位置。\n */\nfunction resolveScreenshotSaveDir(\n ctx: ScreenshotOutputContext\n): string {\n const saveDir = ctx.options.screenshot.saveDir.trim()\n\n if (!saveDir) {\n throw new Error('screenshot.saveDir must be a non-empty string')\n }\n\n const root = ctx.server?.config.root\n\n if (!root) {\n throw new Error('Vite server root is required for screenshot path output')\n }\n\n if (path.isAbsolute(saveDir)) {\n return saveDir\n }\n\n return path.resolve(root, saveDir)\n}\n\n/**\n * 生成截图文件名。\n *\n * 文件名只使用服务端生成的安全字段,避免 selector、URL 等外部输入污染路径。\n */\nfunction createScreenshotFileName(payload: ScreenshotImagePayload): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n const suffix = randomUUID().slice(0, 8)\n\n return `${timestamp}-${payload.source}-${payload.target}-${suffix}.${payload.format}`\n}\n\n/**\n * 生成项目相对路径。\n *\n * 返回值统一使用 `/`,让不同操作系统下的 MCP 结果更稳定。\n */\nfunction createProjectRelativePath(\n ctx: ScreenshotOutputContext,\n filePath: string\n): string {\n const root = ctx.server?.config.root\n\n if (!root) {\n throw new Error('Vite server root is required for screenshot path output')\n }\n\n return path.relative(root, filePath).split(path.sep).join('/')\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 reloadPage: () => undefined,\n onPageReloaded: (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 { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport type { IndexHtmlTransformResult, ResolvedConfig } from 'vite'\nimport {\n RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID,\n RESOLVED_VIRTUAL_RUNTIME_ID,\n RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID,\n VIRTUAL_SNAPDOM_LOADER_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 if (importee === VIRTUAL_SNAPDOM_LOADER_ID) {\n return RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID\n }\n\n return undefined\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {\n return createRuntimeModule()\n }\n\n if (id === RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID) {\n return createScreenshotConfigModule(options)\n }\n\n if (id === RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID) {\n return createSnapdomLoaderModule(getConfig()?.root)\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 * 生成浏览器 runtime 入口模块。\n *\n * screenshot 配置必须在 Vite 虚拟模块里解析,但发布包 runtime 不能直接 import 虚拟模块;\n * 因此由这个宿主项目内的虚拟入口完成注册,再启动通用 runtime client。\n */\nfunction createRuntimeModule(): string {\n return [\n \"import { setScreenshotModuleRegistry, setSnapdomLoader, startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';\",\n `import { screenshotModuleRegistry } from '${VIRTUAL_SCREENSHOT_CONFIG_ID}';`,\n `import { loadSnapdom } from '${VIRTUAL_SNAPDOM_LOADER_ID}';`,\n 'setScreenshotModuleRegistry(screenshotModuleRegistry);',\n 'setSnapdomLoader(loadSnapdom);',\n 'void startRuntimeClient();'\n ].join('\\n')\n}\n\n/**\n * 生成 snapdom loader 虚拟模块。\n *\n * optional peer 只能在宿主项目里解析;失败时也要导出 loader,让 runtime 可以把错误返回给 MCP。\n */\nfunction createSnapdomLoaderModule(root?: string): string {\n if (!canResolveSnapdomFromProject(root)) {\n return [\n 'export const loadSnapdom = () =>',\n ` Promise.reject(new Error(${JSON.stringify(createMissingSnapdomMessage())}));`\n ].join('\\n')\n }\n\n return [\n \"import { snapdom } from '@zumer/snapdom';\",\n 'export const loadSnapdom = () => Promise.resolve({ snapdom });'\n ].join('\\n')\n}\n\n/**\n * 判断宿主项目是否安装 snapdom。\n *\n * 使用项目根目录创建 require 可以模拟 Vite 对 peer dependency 的解析边界,避免误用本插件自身依赖。\n */\nfunction canResolveSnapdomFromProject(root?: string): boolean {\n try {\n createRequire(join(root ?? process.cwd(), 'package.json')).resolve(\n '@zumer/snapdom'\n )\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 创建缺失 snapdom 的提示。\n *\n * 统一文案可以让虚拟模块和 runtime 默认错误保持一致,便于 MCP 客户端直接展示修复命令。\n */\nfunction createMissingSnapdomMessage(): string {\n return '缺少可选依赖 @zumer/snapdom。DOM 截图降级需要该依赖,请执行:pnpm add -D @zumer/snapdom'\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":["z","z","snapshot","nodes","z","z","z","z","z","z","z","path","z","nanoid","z","z","path","nanoid","nanoid","nanoid","nanoid","nanoid","path","fs","path","fs","path","isPlainRecord","formatError","readOptionalTextFile","isNodeError","path"]}
1
+ {"version":3,"sources":["../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/mcp/tools/pages.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/screenshot.ts","../src/cdp/cdpScreenshot.ts","../src/mcp/tools/screenshotOutput.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","../src/plugin/skillConfig/index.ts","../src/plugin/skillConfig/writers.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from 'vite'\nimport { searchForWorkspaceRoot } from 'vite'\nimport { mergeOptions, RUNTIME_PAGE_RECONNECTED_EVENT } 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 { updateSkillConfigs } from './skillConfig'\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.server = 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 ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, 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 userOptions\n )\n await updateSkillConfigs(root, options.skill)\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 DEFAULT_SCREENSHOT_SAVE_DIR = '.vite-mcp/screenshot'\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n reloadPage: 'reload_page',\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/** snapdom loader 虚拟模块 ID,用于把 optional peer 解析限制在宿主 Vite 模块图里。 */\nexport const VIRTUAL_SNAPDOM_LOADER_ID =\n 'virtual:vite-plugin-vue-mcp-next/snapdom-loader'\n\n/** Vite 内部解析 snapdom loader 时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\\0${VIRTUAL_SNAPDOM_LOADER_ID}`\n\n/** 默认 MCP 客户端服务名,采用 Vite 维度命名以匹配插件能力边界。 */\nexport const DEFAULT_MCP_CLIENT_SERVER_NAME = 'vite-mcp-next'\n\n/** 旧默认服务名只用于迁移已有配置,避免用户项目里同时出现新旧两份 MCP 配置。 */\nexport const LEGACY_MCP_CLIENT_SERVER_NAMES = ['vue-mcp-next'] as const\n\n/** Runtime 页面重连事件名,供 reload_page 等待页面刷新后重新接入。 */\nexport const RUNTIME_PAGE_RECONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-reconnected'\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 skill: {\n autoConfig: true\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 type: 'path',\n saveDir: DEFAULT_SCREENSHOT_SAVE_DIR,\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 skill: {\n ...DEFAULT_OPTIONS.skill,\n ...options.skill\n },\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: 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 type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport type { ViteDevServer } from 'vite'\nimport { createCdpClient } from '../../cdp/cdpClient'\nimport { MCP_TOOL_NAMES, RUNTIME_PAGE_RECONNECTED_EVENT } from '../../constants'\nimport { discoverHtmlEntries } from '../../plugin/entryDiscovery'\nimport type { PageTarget, VueMcpNextContext } from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} 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 server.registerTool(\n MCP_TOOL_NAMES.reloadPage,\n {\n description:\n 'Reload the selected page. CDP uses ignoreCache; Runtime Hook falls back to normal reload.',\n inputSchema: {\n pageId: z.string().optional(),\n ignoreCache: z.boolean().optional()\n }\n },\n async (input) => {\n if (hasCdpConfig(ctx)) {\n return reloadPageWithCdp(ctx, input.pageId, input.ignoreCache ?? true)\n }\n\n const target = resolveRuntimeReloadTarget(ctx, input.pageId)\n\n if (!target.ok) {\n return createToolError(target.error)\n }\n\n const reconnect = waitForRuntimePageReconnect(ctx)\n ctx.pages.disconnect(target.page.pageId)\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.reloadPage({ event })\n })\n\n if (!isRecord(result) || result.ok === false) {\n reconnect.cancel()\n\n return createToolResponse(\n isRecord(result)\n ? result\n : { ok: false, error: 'Invalid runtime reload response' }\n )\n }\n\n const page = await reconnect.promise\n\n return createToolResponse(\n page\n ? { ...result, reconnected: true, pageId: page.pageId, page }\n : {\n ...result,\n reconnected: false,\n error: 'runtime page reconnect timed out'\n }\n )\n }\n )\n}\n\n/**\n * 判断是否应进入 CDP 刷新路径。\n *\n * 刷新工具的语义和 DOM/Evaluate 不同:只要用户显式配置了 CDP,就应该使用浏览器协议的\n * `ignoreCache` 能力;未配置时才退回 Runtime Hook 普通刷新。\n */\nfunction hasCdpConfig(ctx: VueMcpNextContext): boolean {\n return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint)\n}\n\n/**\n * 校验 Runtime RPC 回包是否可作为 MCP structuredContent。\n *\n * Runtime 通道来自浏览器页面,服务端需要把未知值收窄为对象,避免 MCP SDK 的结构化响应类型\n * 接收到数组或原始值。\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * 解析 Runtime 刷新的目标页面。\n *\n * Runtime reload 会让旧 bridge 失效,因此刷新前必须先定位并标记旧 pageId,\n * 避免 `list_pages` 在新页面连接后同时保留两个可用目标。\n */\nfunction resolveRuntimeReloadTarget(\n ctx: VueMcpNextContext,\n pageId?: string\n): { ok: true; page: PageTarget } | { ok: false; error: string } {\n try {\n const page = resolvePageTarget(ctx, pageId)\n\n if (page.source !== 'runtime') {\n return {\n ok: false,\n error: 'Runtime reload requires a runtime page target'\n }\n }\n\n return { ok: true, page }\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 等待刷新后的 Runtime 页面重新接入。\n *\n * 该等待只用于确认页面 bridge 已经重新建立;超时返回 null,让调用方可以把“已触发但未确认”\n * 明确暴露给 MCP 客户端,而不是无限挂起。\n */\nfunction waitForRuntimePageReconnect(ctx: VueMcpNextContext): {\n readonly promise: Promise<PageTarget | null>\n cancel(): void\n} {\n let timeout: NodeJS.Timeout | undefined\n let cleanup: (() => void) | undefined\n const promise = new Promise<PageTarget | null>((resolve) => {\n timeout = setTimeout(() => {\n cleanup?.()\n resolve(null)\n }, 5000)\n cleanup = ctx.hooks.hookOnce(RUNTIME_PAGE_RECONNECTED_EVENT, (payload) => {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n resolve(isPageTarget(payload) ? payload : null)\n })\n })\n\n return {\n promise,\n cancel() {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n cleanup?.()\n }\n }\n}\n\n/**\n * 校验页面重连事件载荷。\n *\n * 事件来自浏览器运行时,刷新工具只依赖页面目标最小字段,避免把异常 payload 当成刷新完成。\n */\nfunction isPageTarget(value: unknown): value is PageTarget {\n if (!isRecord(value)) {\n return false\n }\n\n return (\n typeof value.pageId === 'string' &&\n (value.source === 'runtime' || value.source === 'cdp') &&\n typeof value.url === 'string' &&\n typeof value.pathname === 'string' &&\n typeof value.connected === 'boolean'\n )\n}\n\n/**\n * 通过 CDP 执行页面刷新。\n *\n * `ignoreCache` 是 CDP 的标准刷新参数,适合测试前规避浏览器 HTTP 缓存;\n * 连接生命周期仍保持按工具调用即连即关,避免开发服务器长期占用调试连接。\n */\nasync function reloadPageWithCdp(\n ctx: VueMcpNextContext,\n pageId: string | undefined,\n ignoreCache: boolean\n) {\n const cdp = await connectCdpForPage(ctx, pageId)\n\n if (!cdp) {\n return createToolError('CDP target is unavailable for page reload')\n }\n\n try {\n await cdp.client.Page.enable()\n const loaded = cdp.client.Page.loadEventFired()\n await cdp.client.Page.reload({ ignoreCache })\n await loaded\n\n return createToolResponse({\n ok: true,\n source: 'cdp',\n ignoreCache,\n pageId\n })\n } finally {\n await closeCdpClient(cdp.client)\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 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","/**\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'\nimport {\n createScreenshotOutput,\n type ScreenshotImagePayload\n} from './screenshotOutput'\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 await 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 if (result.ok === false) {\n return createToolResponse(result)\n }\n\n if (!isScreenshotImagePayload(result)) {\n return createToolError('runtime screenshot returned an invalid response')\n }\n\n return createScreenshotResponse(ctx, {\n ...result,\n target: normalized.target,\n format: normalized.format\n })\n}\n\n/**\n * 创建截图响应。\n *\n * CDP 和 runtime 都必须经过同一个体积限制,避免某条通道绕过 MCP 响应保护。\n */\nasync function createScreenshotResponse(\n ctx: VueMcpNextContext,\n result: ScreenshotImagePayload\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 try {\n return createToolResponse(await createScreenshotOutput(ctx, result))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n return createToolError(`failed to create screenshot output: ${message}`)\n }\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 * 校验 runtime 成功截图结果。\n *\n * 浏览器 runtime 返回 unknown,服务端必须确认图片字段完整后才能写入文件系统。\n */\nfunction isScreenshotImagePayload(\n result: Record<string, unknown>\n): result is ScreenshotImagePayload {\n return (\n (result.source === 'cdp' || result.source === 'snapdom') &&\n typeof result.data === 'string' &&\n typeof result.width === 'number' &&\n typeof result.height === 'number' &&\n typeof result.mimeType === 'string' &&\n typeof result.byteLength === 'number'\n )\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","/**\n * 服务端截图输出工具。\n *\n * CDP 与浏览器 runtime 都只能稳定产出图片数据,项目路径写入必须在 Vite dev server 侧统一处理。\n */\nimport { randomUUID } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type {\n ResolvedVueMcpNextOptions,\n ScreenshotFormat,\n ScreenshotTarget\n} from '../../types'\n\n/** 截图来源,调用方需要用它解释 CDP 真截图与 snapdom DOM 截图的差异。 */\nexport type ScreenshotOutputSource = 'cdp' | 'snapdom'\n\n/** 截图原始数据,输出 helper 会按项目配置转换为路径或 base64 响应。 */\nexport interface ScreenshotImagePayload {\n readonly [key: string]: unknown\n /** 截图来源,适合调用方判断截图可信度和限制。 */\n readonly source: ScreenshotOutputSource\n /** 截图范围,用于文件名和返回元数据。 */\n readonly target: ScreenshotTarget\n /** 图片格式,用于 mime type 和扩展名保持一致。 */\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,便于客户端解码。 */\n readonly mimeType: string\n /** 原始字节数,用于体积限制和结果说明。 */\n readonly byteLength: number\n /** runtime DOM 截图的已知限制,CDP 截图通常不需要该字段。 */\n readonly limitations?: readonly string[]\n}\n\n/** 路径输出结果,默认用于项目级 MCP,避免 base64 占用模型上下文。 */\nexport interface ScreenshotPathOutput\n extends Omit<ScreenshotImagePayload, 'data'> {\n /** 截图文件绝对路径,适合 MCP 客户端直接读取。 */\n readonly path: string\n /** 相对 Vite 项目根目录路径,适合用户在项目内定位。 */\n readonly relativePath: string\n}\n\n/** 截图输出结果,项目配置决定返回路径还是保留 base64 数据。 */\nexport type ScreenshotOutput = ScreenshotImagePayload | ScreenshotPathOutput\n\n/** 截图输出所需的最小服务端上下文,避免把 helper 绑定到完整 ViteDevServer 实例。 */\nexport interface ScreenshotOutputContext {\n /** 已解析插件配置,输出策略只读取项目级截图配置。 */\n readonly options: ResolvedVueMcpNextOptions\n /** Vite 项目根目录来源,path 模式需要它解析相对 saveDir。 */\n readonly server?: {\n readonly config: {\n readonly root: string\n }\n }\n}\n\n/**\n * 创建截图输出。\n *\n * 该函数集中处理项目级输出策略,让 CDP 和 runtime 通道不关心文件系统细节。\n */\nexport async function createScreenshotOutput(\n ctx: ScreenshotOutputContext,\n payload: ScreenshotImagePayload\n): Promise<ScreenshotOutput> {\n if (ctx.options.screenshot.type === 'base64') {\n return payload\n }\n\n const saveDir = resolveScreenshotSaveDir(ctx)\n await mkdir(saveDir, { recursive: true })\n const filePath = path.join(saveDir, createScreenshotFileName(payload))\n await writeFile(filePath, Buffer.from(payload.data, 'base64'))\n\n return {\n source: payload.source,\n target: payload.target,\n format: payload.format,\n width: payload.width,\n height: payload.height,\n mimeType: payload.mimeType,\n byteLength: payload.byteLength,\n limitations: payload.limitations,\n path: filePath,\n relativePath: createProjectRelativePath(ctx, filePath)\n }\n}\n\n/**\n * 解析截图保存目录。\n *\n * 相对路径必须基于 Vite root,而不是当前 shell 工作目录,否则 monorepo 中会写错项目位置。\n */\nfunction resolveScreenshotSaveDir(\n ctx: ScreenshotOutputContext\n): string {\n const saveDir = ctx.options.screenshot.saveDir.trim()\n\n if (!saveDir) {\n throw new Error('screenshot.saveDir must be a non-empty string')\n }\n\n const root = ctx.server?.config.root\n\n if (!root) {\n throw new Error('Vite server root is required for screenshot path output')\n }\n\n if (path.isAbsolute(saveDir)) {\n return saveDir\n }\n\n return path.resolve(root, saveDir)\n}\n\n/**\n * 生成截图文件名。\n *\n * 文件名只使用服务端生成的安全字段,避免 selector、URL 等外部输入污染路径。\n */\nfunction createScreenshotFileName(payload: ScreenshotImagePayload): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n const suffix = randomUUID().slice(0, 8)\n\n return `${timestamp}-${payload.source}-${payload.target}-${suffix}.${payload.format}`\n}\n\n/**\n * 生成项目相对路径。\n *\n * 返回值统一使用 `/`,让不同操作系统下的 MCP 结果更稳定。\n */\nfunction createProjectRelativePath(\n ctx: ScreenshotOutputContext,\n filePath: string\n): string {\n const root = ctx.server?.config.root\n\n if (!root) {\n throw new Error('Vite server root is required for screenshot path output')\n }\n\n return path.relative(root, filePath).split(path.sep).join('/')\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 reloadPage: () => undefined,\n onPageReloaded: (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 { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport type { IndexHtmlTransformResult, ResolvedConfig } from 'vite'\nimport {\n RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID,\n RESOLVED_VIRTUAL_RUNTIME_ID,\n RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID,\n VIRTUAL_SNAPDOM_LOADER_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 if (importee === VIRTUAL_SNAPDOM_LOADER_ID) {\n return RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID\n }\n\n return undefined\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {\n return createRuntimeModule()\n }\n\n if (id === RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID) {\n return createScreenshotConfigModule(options)\n }\n\n if (id === RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID) {\n return createSnapdomLoaderModule(getConfig()?.root)\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 * 生成浏览器 runtime 入口模块。\n *\n * screenshot 配置必须在 Vite 虚拟模块里解析,但发布包 runtime 不能直接 import 虚拟模块;\n * 因此由这个宿主项目内的虚拟入口完成注册,再启动通用 runtime client。\n */\nfunction createRuntimeModule(): string {\n return [\n \"import { setScreenshotModuleRegistry, setSnapdomLoader, startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';\",\n `import { screenshotModuleRegistry } from '${VIRTUAL_SCREENSHOT_CONFIG_ID}';`,\n `import { loadSnapdom } from '${VIRTUAL_SNAPDOM_LOADER_ID}';`,\n 'setScreenshotModuleRegistry(screenshotModuleRegistry);',\n 'setSnapdomLoader(loadSnapdom);',\n 'void startRuntimeClient();'\n ].join('\\n')\n}\n\n/**\n * 生成 snapdom loader 虚拟模块。\n *\n * optional peer 只能在宿主项目里解析;失败时也要导出 loader,让 runtime 可以把错误返回给 MCP。\n */\nfunction createSnapdomLoaderModule(root?: string): string {\n if (!canResolveSnapdomFromProject(root)) {\n return [\n 'export const loadSnapdom = () =>',\n ` Promise.reject(new Error(${JSON.stringify(createMissingSnapdomMessage())}));`\n ].join('\\n')\n }\n\n return [\n \"import { snapdom } from '@zumer/snapdom';\",\n 'export const loadSnapdom = () => Promise.resolve({ snapdom });'\n ].join('\\n')\n}\n\n/**\n * 判断宿主项目是否安装 snapdom。\n *\n * 使用项目根目录创建 require 可以模拟 Vite 对 peer dependency 的解析边界,避免误用本插件自身依赖。\n */\nfunction canResolveSnapdomFromProject(root?: string): boolean {\n try {\n createRequire(join(root ?? process.cwd(), 'package.json')).resolve(\n '@zumer/snapdom'\n )\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 创建缺失 snapdom 的提示。\n *\n * 统一文案可以让虚拟模块和 runtime 默认错误保持一致,便于 MCP 客户端直接展示修复命令。\n */\nfunction createMissingSnapdomMessage(): string {\n return '缺少可选依赖 @zumer/snapdom。DOM 截图降级需要该依赖,请执行:pnpm add -D @zumer/snapdom'\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","/**\n * MCP 客户端配置编排模块。\n *\n * 这里负责判断当前项目应该写入哪些客户端配置;真正的 JSON/TOML 写入仍由独立 writer 负责,\n * 这样可以把“是否应该写”和“如何安全写”分开测试,避免自动探测误改用户已有配置。\n */\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {\n DEFAULT_MCP_CLIENT_SERVER_NAME,\n LEGACY_MCP_CLIENT_SERVER_NAMES\n} from '../../constants'\nimport type {\n ResolvedVueMcpNextOptions,\n VueMcpNextOptions\n} 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/** 支持自动写入项目级 MCP 配置的客户端名称。 */\ntype McpClientName = 'cursor' | 'codex' | 'claudeCode' | 'trae'\n\n/** 客户端入口类型用于区分目录型入口和文件型入口。 */\ntype ClientEntryKind = 'directory' | 'file'\n\n/** 单个客户端的写入决策上下文,使用对象参数避免后续增加字段时拉长参数列表。 */\ninterface ClientUpdateDecisionOptions {\n /** 项目根目录,所有客户端入口都基于该目录判断。 */\n readonly root: string\n /** 当前客户端名称,用于查找用户是否显式配置。 */\n readonly clientName: McpClientName\n /** 解析后的开关值,`false` 表示无条件跳过。 */\n readonly enabled: boolean\n /** 自动探测使用的项目入口路径。 */\n readonly entryPath: string\n /** 入口类型,目录型客户端不能被同名文件误判为已启用。 */\n readonly entryKind: ClientEntryKind\n /** 用户原始配置,用于区分默认启用和显式启用。 */\n readonly userOptions: VueMcpNextOptions\n}\n\n/** 单个 MCP 客户端的配置写入描述,统一承载探测入口和实际写入动作。 */\ninterface ClientConfigDescriptor extends ClientUpdateDecisionOptions {\n /** 通过探测后执行的配置写入任务。 */\n readonly createJob: () => Promise<void>\n}\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 userOptions: VueMcpNextOptions = {}\n): Promise<void> {\n const serverName = options.serverName\n const legacyServerNames = getLegacyServerNames(serverName)\n const descriptors: readonly ClientConfigDescriptor[] = [\n {\n root,\n clientName: 'cursor',\n enabled: options.cursor,\n entryPath: path.join(root, '.cursor'),\n entryKind: 'directory',\n userOptions,\n createJob: () =>\n updateJsonMcpClientConfig({\n clientName: 'Cursor',\n configPath: path.join(root, '.cursor', 'mcp.json'),\n mcpUrl: sseUrl,\n serverName,\n legacyServerNames\n })\n },\n {\n root,\n clientName: 'codex',\n enabled: options.codex,\n entryPath: path.join(root, '.codex'),\n entryKind: 'directory',\n userOptions,\n createJob: () =>\n updateCodexMcpClientConfig({\n configPath: path.join(root, '.codex', 'config.toml'),\n mcpUrl: streamableHttpUrl,\n serverName,\n legacyServerNames\n })\n },\n {\n root,\n clientName: 'claudeCode',\n enabled: options.claudeCode,\n entryPath: path.join(root, '.mcp.json'),\n entryKind: 'file',\n userOptions,\n createJob: () =>\n updateJsonMcpClientConfig({\n clientName: 'Claude Code',\n configPath: path.join(root, '.mcp.json'),\n mcpUrl: sseUrl,\n serverName,\n legacyServerNames\n })\n },\n {\n root,\n clientName: 'trae',\n enabled: options.trae,\n entryPath: path.join(root, '.trae'),\n entryKind: 'directory',\n userOptions,\n createJob: () =>\n updateJsonMcpClientConfig({\n clientName: 'Trae',\n configPath: path.join(root, '.trae', 'mcp.json'),\n mcpUrl: sseUrl,\n serverName,\n legacyServerNames\n })\n }\n ]\n\n const jobs = await createClientConfigJobs(descriptors)\n await Promise.all(jobs)\n}\n\nasync function createClientConfigJobs(\n descriptors: readonly ClientConfigDescriptor[]\n): Promise<Promise<void>[]> {\n const jobs: Promise<void>[] = []\n\n for (const descriptor of descriptors) {\n if (await shouldUpdateClientConfig(descriptor)) {\n jobs.push(descriptor.createJob())\n }\n }\n\n return jobs\n}\n\n/**\n * 只有默认服务名使用旧名迁移。\n *\n * 用户显式配置自定义 `serverName` 时应按自定义名创建,不能被历史默认名阻断。\n */\nfunction getLegacyServerNames(serverName: string): readonly string[] {\n return serverName === DEFAULT_MCP_CLIENT_SERVER_NAME\n ? LEGACY_MCP_CLIENT_SERVER_NAMES\n : []\n}\n\n/**\n * 判断某个客户端本次是否应该尝试写入配置。\n *\n * 默认启用只代表“允许自动探测”;只有用户显式传 `true` 才代表强制创建,\n * 这样可以避免一个普通 Vite 项目启动后被创建所有 AI 客户端配置目录。\n */\nasync function shouldUpdateClientConfig(\n options: ClientUpdateDecisionOptions\n): Promise<boolean> {\n if (!options.enabled) {\n return false\n }\n\n if (isClientExplicitlyConfigured(options.clientName, options.userOptions)) {\n return true\n }\n\n return hasExpectedEntry(options.entryPath, options.entryKind)\n}\n\n/**\n * 判断客户端开关是否来自用户显式配置。\n *\n * Cursor 需要兼容旧的 `updateCursorMcpJson`,因为旧入口本身就表达了用户对 Cursor 配置的明确意图。\n */\nfunction isClientExplicitlyConfigured(\n clientName: McpClientName,\n userOptions: VueMcpNextOptions\n): boolean {\n if (Object.hasOwn(userOptions.mcpClients ?? {}, clientName)) {\n return true\n }\n\n return clientName === 'cursor' && userOptions.updateCursorMcpJson !== undefined\n}\n\n/**\n * 检查项目中是否已经存在对应客户端入口。\n *\n * 目录型入口必须真的是目录,文件型入口必须真的是文件,避免同名异常文件导致插件误写配置。\n */\nasync function hasExpectedEntry(\n entryPath: string,\n entryKind: ClientEntryKind\n): Promise<boolean> {\n try {\n const stat = await fs.stat(entryPath)\n return entryKind === 'directory' ? stat.isDirectory() : stat.isFile()\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return false\n }\n\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to inspect MCP client entry at ${entryPath}: ${formatError(error)}`\n )\n return false\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","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 readonly legacyServerNames?: readonly 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 = createServerTableMatcher(options.serverName)\n\n if (matcher.test(current)) {\n return ensureTrailingNewline(current)\n }\n\n const legacyServerName = options.legacyServerNames?.find((serverName) =>\n createServerTableMatcher(serverName).test(current)\n )\n if (legacyServerName) {\n return ensureTrailingNewline(\n renameServerTableHeaders(current, legacyServerName, options.serverName)\n )\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 createServerTableMatcher(serverName: string): RegExp {\n const plainHeader = escapeRegExp(`[mcp_servers.${serverName}]`)\n const plainChildHeader = escapeRegExp(`[mcp_servers.${serverName}.`)\n const quotedHeader = escapeRegExp(\n `[mcp_servers.${quoteTomlKey(serverName)}]`\n )\n const quotedChildHeader = escapeRegExp(\n `[mcp_servers.${quoteTomlKey(serverName)}.`\n )\n\n return new RegExp(\n `(?:^|\\\\n)(?:${plainHeader}|${plainChildHeader}|${quotedHeader}|${quotedChildHeader})`\n )\n}\n\nfunction createTableHeader(serverName: string): string {\n const key = createTableKey(serverName)\n return `[mcp_servers.${key}]`\n}\n\nfunction createTableKey(serverName: string): string {\n return /^[A-Za-z0-9_-]+$/.test(serverName)\n ? serverName\n : quoteTomlKey(serverName)\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\n/**\n * 重命名 Codex TOML 中本插件服务表头。\n *\n * 只替换表头中的服务名,保留 url、env、headers 等用户已有字段,避免迁移时改变真实连接参数。\n */\nfunction renameServerTableHeaders(\n current: string,\n fromServerName: string,\n toServerName: string\n): string {\n return current\n .split('\\n')\n .map((line) => renameServerTableHeader(line, fromServerName, toServerName))\n .join('\\n')\n}\n\nfunction renameServerTableHeader(\n line: string,\n fromServerName: string,\n toServerName: string\n): string {\n const toKey = createTableKey(toServerName)\n const fromKeys = [fromServerName, quoteTomlKey(fromServerName)]\n\n for (const fromKey of fromKeys) {\n const prefix = `[mcp_servers.${fromKey}`\n const nextChar = line[prefix.length]\n\n if (line.startsWith(prefix) && (nextChar === ']' || nextChar === '.')) {\n return `[mcp_servers.${toKey}${line.slice(prefix.length)}`\n }\n }\n\n return line\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 readonly legacyServerNames?: readonly 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 const migratedMcpServers = renameLegacyServer(mcpServers, options)\n if (migratedMcpServers) {\n config.mcpServers = migratedMcpServers\n await writeJsonConfig(options.configPath, config)\n return\n }\n\n mcpServers[options.serverName] = { type: 'sse', url: options.mcpUrl }\n config.mcpServers = mcpServers\n\n await writeJsonConfig(options.configPath, config)\n } catch (error) {\n warnConfigFailure(options, formatError(error))\n }\n}\n\n/**\n * 将旧默认服务名改成新默认服务名。\n *\n * 只在新名称不存在时迁移,避免新旧配置同时存在时误合并用户手动调整过的两份配置。\n */\nfunction renameLegacyServer(\n mcpServers: Record<string, unknown>,\n options: UpdateJsonMcpClientConfigOptions\n): Record<string, unknown> | undefined {\n const legacyServerName = options.legacyServerNames?.find((name) =>\n Object.hasOwn(mcpServers, name)\n )\n\n if (!legacyServerName) {\n return undefined\n }\n\n return Object.fromEntries(\n Object.entries(mcpServers).map(([serverName, serverConfig]) => [\n serverName === legacyServerName ? options.serverName : serverName,\n serverConfig\n ])\n )\n}\n\nasync function writeJsonConfig(\n configPath: string,\n config: Record<string, unknown>\n): Promise<void> {\n await fs.mkdir(path.dirname(configPath), { recursive: true })\n await fs.writeFile(configPath, `${JSON.stringify(config, null, 2)}\\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","import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport type { ResolvedVueMcpNextOptions } from '../../types'\nimport { writeGeneratedTextFile } from './writers'\n\nconst PACKAGE_NAME = '@xiaou66/vite-plugin-vue-mcp-next'\nconst PACKAGED_SKILL_PATH = path.join('skills', 'vite-mcp-next', 'SKILL.md')\n\n/** AI 使用指南写入器只需要 resolved 后的 skill 字段,测试可直接传入该字段。 */\nexport type ResolvedSkillConfigOptions = ResolvedVueMcpNextOptions['skill']\n\n/** 支持自动安装使用指南的客户端入口描述。 */\ninterface SkillConfigDescriptor {\n /** 入口目录存在时才自动安装,避免污染未使用的客户端配置。 */\n readonly entryPath: string\n /** 目标文件路径,只写本插件拥有的 skill/rule 文件。 */\n readonly filePath: string\n /** 日志目标名称,用于跳过或失败时定位。 */\n readonly targetName: string\n}\n\n/**\n * 自动安装 AI 使用指南。\n *\n * 该能力只增强 AI 客户端上下文,不参与 MCP 服务启动;任何写入失败都只记录警告,\n * 不能阻断 Vite dev server,因为调试服务本身仍然可以正常工作。\n */\nexport async function updateSkillConfigs(\n root: string,\n options: ResolvedSkillConfigOptions\n): Promise<void> {\n if (!options.autoConfig) {\n return\n }\n\n const descriptors = createSkillConfigDescriptors(root)\n const skillContent = await safelyReadPackagedSkillContent(root)\n if (!skillContent) {\n return\n }\n\n const jobs = await createSkillConfigJobs(descriptors, skillContent)\n await Promise.all(jobs)\n}\n\nfunction createSkillConfigDescriptors(\n root: string\n): readonly SkillConfigDescriptor[] {\n return [\n {\n entryPath: path.join(root, '.codex'),\n filePath: path.join(root, '.codex', 'skills', 'vite-mcp-next', 'SKILL.md'),\n targetName: 'Codex skill'\n },\n {\n entryPath: path.join(root, '.claude'),\n filePath: path.join(\n root,\n '.claude',\n 'skills',\n 'vite-mcp-next',\n 'SKILL.md'\n ),\n targetName: 'Claude Code skill'\n },\n {\n entryPath: path.join(root, '.cursor'),\n filePath: path.join(root, '.cursor', 'rules', 'vite-mcp-next.mdc'),\n targetName: 'Cursor rule'\n }\n ]\n}\n\nasync function createSkillConfigJobs(\n descriptors: readonly SkillConfigDescriptor[],\n content: string\n): Promise<Promise<void>[]> {\n const jobs: Promise<void>[] = []\n\n for (const descriptor of descriptors) {\n if (await hasDirectoryEntry(descriptor.entryPath)) {\n jobs.push(\n writeGeneratedTextFile({\n filePath: descriptor.filePath,\n content,\n targetName: descriptor.targetName\n })\n )\n }\n }\n\n return jobs\n}\n\n/**\n * 读取随 npm 包发布的静态 Skill 文件。\n *\n * 开发态通过源码路径读取项目根目录 `skills`;构建后通过 `dist/index.js` 相邻的包根目录读取,\n * 避免把 Skill 正文硬编码到 TypeScript 字符串里,也让发布包中的文件成为唯一内容来源。\n */\nasync function readPackagedSkillContent(root: string): Promise<string> {\n const candidates = getPackagedSkillCandidates(root)\n\n for (const candidate of candidates) {\n try {\n return await fs.readFile(candidate, 'utf-8')\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n continue\n }\n\n throw error\n }\n }\n\n throw new Error(\n `Cannot find packaged vite-mcp-next skill at ${candidates.join(', ')}`\n )\n}\n\nasync function safelyReadPackagedSkillContent(\n root: string\n): Promise<string | undefined> {\n try {\n return await readPackagedSkillContent(root)\n } catch (error) {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to read packaged AI skill: ${formatError(error)}`\n )\n return undefined\n }\n}\n\nfunction getPackagedSkillCandidates(root: string): string[] {\n return [\n path.resolve(root, 'node_modules', PACKAGE_NAME, PACKAGED_SKILL_PATH),\n path.resolve(process.cwd(), 'node_modules', PACKAGE_NAME, PACKAGED_SKILL_PATH),\n path.resolve(process.cwd(), PACKAGED_SKILL_PATH)\n ]\n}\n\nasync function hasDirectoryEntry(entryPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(entryPath)\n return stat.isDirectory()\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return false\n }\n\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to inspect skill config entry at ${entryPath}: ${formatError(error)}`\n )\n return false\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","/**\n * AI 使用指南生成文件写入工具。\n *\n * 该模块只负责写入插件拥有的 skill/rule 文件,适用于 Vite dev server 启动时补充 AI 客户端上下文;\n * 通过生成标记保护用户手写文件,避免开发服务启动过程覆盖用户定制内容。\n */\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/** 自动生成文件标记,用于区分插件拥有的文件和用户手写文件。 */\nexport const GENERATED_SKILL_CONFIG_MARKER =\n '<!-- Generated by vite-plugin-vue-mcp-next. Safe to edit, but automatic updates only apply while this marker remains. -->'\n\n/**\n * 自动生成文本文件写入参数。\n *\n * 使用对象参数是为了后续扩展 dry-run、日志策略或生成来源时不破坏调用方签名。\n */\nexport interface WriteGeneratedTextFileOptions {\n /** 目标文件路径,调用方负责按客户端规则传入项目级路径。 */\n readonly filePath: string\n /** 完整文件内容,必须包含生成标记才能允许后续自动更新。 */\n readonly content: string\n /** 日志中的目标名称,用于用户定位是哪类客户端配置被跳过。 */\n readonly targetName: string\n}\n\n/**\n * 写入插件拥有的生成文件。\n *\n * 只有缺失文件或带生成标记的文件会被写入;没有标记的已有文件视为用户手写内容,\n * 必须跳过以避免启动 Vite 时覆盖用户对 AI 客户端上下文的定制。\n */\nexport async function writeGeneratedTextFile(\n options: WriteGeneratedTextFileOptions\n): Promise<void> {\n try {\n const current = await readOptionalTextFile(options.filePath)\n\n if (current && !current.includes(GENERATED_SKILL_CONFIG_MARKER)) {\n console.warn(\n `[vite-plugin-vue-mcp-next] Skipped ${options.targetName} at ${options.filePath}: file is not generated by this plugin`\n )\n return\n }\n\n await fs.mkdir(path.dirname(options.filePath), { recursive: true })\n await fs.writeFile(options.filePath, options.content)\n } catch (error) {\n console.warn(\n `[vite-plugin-vue-mcp-next] Failed to update ${options.targetName} at ${options.filePath}: ${formatError(error)}`\n )\n }\n}\n\n/**\n * 读取可选文本文件。\n *\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\n/**\n * 格式化未知错误。\n *\n * 文件写入失败只进入 Vite 启动警告,统一转成字符串可以避免 unknown 直接泄漏到日志格式中。\n */\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * 判断 Node 文件系统错误。\n *\n * 这里只关心 `ENOENT` 这类 errno 字段,使用窄类型保护可以避免对普通 Error 读取不存在字段。\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":["z","z","snapshot","nodes","z","z","z","z","z","z","z","path","z","nanoid","z","z","path","nanoid","nanoid","nanoid","nanoid","nanoid","fs","path","fs","path","fs","path","isPlainRecord","formatError","readOptionalTextFile","isNodeError","path","fs","isNodeError","formatError","fs","path","fs","path","readOptionalTextFile","formatError","isNodeError","path","fs","isNodeError","formatError"]}