@xiaou66/vite-plugin-vue-mcp-next 1.3.0 → 1.3.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/elementContext.ts","../src/shared/elementId.ts","../src/mcp/tools/evaluate.ts","../src/cdp/cdpEvaluate.ts","../src/mcp/tools/network.ts","../src/mcp/tools/performance.ts","../src/performance/summary.ts","../src/performance/output.ts","../src/cdp/cdpPerformance.ts","../src/mcp/tools/pages.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/storage.ts","../src/cdp/cdpStorage.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/elementInstrumentation.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 {\n DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS,\n DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS,\n mergeOptions,\n RUNTIME_PAGE_CONNECTED_EVENT,\n RUNTIME_PAGE_DISCONNECTED_EVENT,\n RUNTIME_PAGE_HEARTBEAT_EVENT,\n RUNTIME_PAGE_RECONNECTED_EVENT\n} from '../constants'\nimport { createVueMcpNextContext } from '../context'\nimport { createMcpServer } from '../mcp/createMcpServer'\nimport { setupMcpTransport } from '../mcp/transport'\nimport { appendPerformanceReport } from '../mcp/tools/performance'\nimport { createServerVueRuntimeRpc } from '../mcp/vueRpc'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PerformanceReport,\n VueMcpNextOptions\n} from '../types'\nimport { createCdpLifecycleController } from './cdpLifecycle'\nimport { createElementInstrumentationController } from './elementInstrumentation'\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 let elementInstrumentation:\n | ReturnType<typeof createElementInstrumentationController>\n | undefined\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 elementInstrumentation = createElementInstrumentationController({\n root: resolvedConfig.root\n })\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 const lastSeenAt = new Map<string, number>()\n const heartbeatTimer = setInterval(() => {\n const now = Date.now()\n\n for (const [pageId, seenAt] of lastSeenAt) {\n const target = ctx.pages.get(pageId)\n\n if (!target || target.source !== 'runtime' || !target.connected) {\n lastSeenAt.delete(pageId)\n continue\n }\n\n if (now - seenAt >= DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS) {\n ctx.pages.disconnect(pageId, now)\n lastSeenAt.delete(pageId)\n }\n }\n }, DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS)\n\n server.ws.on(RUNTIME_PAGE_CONNECTED_EVENT, (payload: unknown) => {\n if (isRuntimePageTarget(payload)) {\n ctx.pages.upsert(payload)\n lastSeenAt.set(payload.pageId, Date.now())\n void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload)\n void cdpLifecycle.connectPage(payload)\n }\n })\n server.ws.on(RUNTIME_PAGE_HEARTBEAT_EVENT, (payload: unknown) => {\n if (isRuntimeHeartbeatTarget(payload)) {\n const target = ctx.pages.get(payload.pageId)\n\n if (target?.source === 'runtime' && target.connected) {\n lastSeenAt.set(payload.pageId, payload.timestamp)\n }\n }\n })\n server.ws.on(RUNTIME_PAGE_DISCONNECTED_EVENT, (payload: unknown) => {\n if (isRuntimeDisconnectTarget(payload)) {\n ctx.pages.disconnect(payload.pageId)\n lastSeenAt.delete(payload.pageId)\n }\n })\n server.ws.on('vite-plugin-vue-mcp-next:console-record', (payload: unknown) => {\n if (isConsoleRecord(payload)) {\n ctx.consoleRecords.push(payload)\n }\n })\n server.ws.on('vite-plugin-vue-mcp-next:network-record', (payload: unknown) => {\n if (isNetworkRecord(payload)) {\n ctx.networkRecords.push(payload)\n }\n })\n server.ws.on(\n 'vite-plugin-vue-mcp-next:performance-record',\n (payload: unknown) => {\n if (isPerformanceReport(payload)) {\n appendPerformanceReport(ctx, 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 clearInterval(heartbeatTimer)\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 const instrumented = elementInstrumentation?.transform(\n code,\n id,\n transformOptions?.ssr\n )\n const nextCode =\n instrumented &&\n typeof instrumented === 'object' &&\n 'code' in instrumented &&\n typeof instrumented.code === 'string'\n ? instrumented.code\n : code\n const runtimeInjected = runtimeInjection.transform(\n nextCode,\n id,\n transformOptions?.ssr\n )\n\n if (runtimeInjected) {\n return runtimeInjected\n }\n\n return instrumented\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 (target.runtimeClientId === undefined ||\n typeof target.runtimeClientId === 'string')\n )\n}\n\n/**\n * 校验 runtime 心跳载荷。\n *\n * 心跳只负责刷新活性时间,不应允许服务端接受结构不完整的数据。\n */\nfunction isRuntimeHeartbeatTarget(\n payload: unknown\n): payload is { readonly pageId: string; readonly timestamp: number } {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<{ pageId: string; timestamp: number }>\n\n return typeof target.pageId === 'string' && typeof target.timestamp === 'number'\n}\n\n/**\n * 校验 runtime 主动断开载荷。\n *\n * 断开事件只需要 pageId,避免把页面卸载过程里的其他状态误当成服务端输入。\n */\nfunction isRuntimeDisconnectTarget(\n payload: unknown\n): payload is { readonly pageId: string } {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<{ pageId: string }>\n\n return typeof target.pageId === 'string'\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 * 校验 performance hook 上报记录。\n *\n * 性能报告由浏览器运行时主动推送,服务端只接收足以完成缓存和查询的最小字段,\n * 避免异常 payload 污染 `get_performance_report` 的结果。\n */\nfunction isPerformanceReport(payload: unknown): payload is PerformanceReport {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const report = payload as Partial<PerformanceReport>\n\n return (\n typeof report.recordingId === 'string' &&\n typeof report.pageId === 'string' &&\n (report.source === 'hook' || report.source === 'cdp') &&\n Boolean(report.summary) &&\n Array.isArray(report.longTasks) &&\n Array.isArray(report.limitations)\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/** 默认性能诊断保存目录,原始 profile 和 heap 文件都应保存在项目内。 */\nexport const DEFAULT_PERFORMANCE_SAVE_DIR = '.vite-mcp/performance'\n\n/** 默认性能报告缓冲上限,避免长时间会话无限累积历史诊断结果。 */\nexport const DEFAULT_PERFORMANCE_MAX_REPORTS = 100\n\n/** 默认性能诊断最大时长,避免一次采集长时间占用浏览器资源。 */\nexport const DEFAULT_PERFORMANCE_MAX_DURATION_MS = 30_000\n\n/** 默认性能诊断采样间隔,兼顾趋势判断和额外采样开销。 */\nexport const DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS = 250\n\n/** 默认长任务阈值,沿用浏览器 Long Task 的常见卡顿判断口径。 */\nexport const DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS = 50\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 listStorage: 'list_storage',\n getStorageItem: 'get_storage_item',\n setStorageItem: 'set_storage_item',\n deleteStorageItem: 'delete_storage_item',\n clearStorage: 'clear_storage',\n recordPerformance: 'record_performance',\n startPerformanceRecording: 'start_performance_recording',\n stopPerformanceRecording: 'stop_performance_recording',\n getPerformanceReport: 'get_performance_report',\n takeHeapSnapshot: 'take_heap_snapshot',\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 getElementContext: 'get_element_context'\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/** Runtime 页面连接事件名,供 runtime client 启动时上报页面进入。 */\nexport const RUNTIME_PAGE_CONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-connected'\n\n/** Runtime 页面断开事件名,供页面卸载时主动通知服务端清理目标。 */\nexport const RUNTIME_PAGE_DISCONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-disconnected'\n\n/** Runtime 页面心跳事件名,供服务端兜底判断页面是否失活。 */\nexport const RUNTIME_PAGE_HEARTBEAT_EVENT =\n 'vite-plugin-vue-mcp-next:heartbeat'\n\n/** Runtime 页面心跳间隔,保持较低流量并覆盖正常关闭场景。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_INTERVAL_MS = 15_000\n\n/** Runtime 页面失活阈值,留出心跳抖动和短暂阻塞的缓冲。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45_000\n\n/** Runtime 页面兜底扫描间隔,和失活阈值保持一致以减少无意义轮询。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45_000\n\n/** 元素选择器轻提示默认时长,足够用户看清复制结果且不长期遮挡页面。 */\nexport const DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS = 2_200\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 elementPicker: {\n enabled: true,\n shortcut: {\n altKey: true,\n shiftKey: true,\n metaKey: false,\n ctrlKey: false\n },\n toastDurationMs: DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS\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 performance: {\n mode: 'auto',\n maxDurationMs: DEFAULT_PERFORMANCE_MAX_DURATION_MS,\n sampleIntervalMs: DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS,\n longTaskThresholdMs: DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS,\n saveDir: DEFAULT_PERFORMANCE_SAVE_DIR,\n memory: {\n enabled: true\n },\n stacks: {\n enabled: true\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 elementPicker: {\n ...DEFAULT_OPTIONS.elementPicker,\n ...options.elementPicker,\n shortcut: {\n ...DEFAULT_OPTIONS.elementPicker.shortcut,\n ...options.elementPicker?.shortcut\n }\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 performance: {\n ...DEFAULT_OPTIONS.performance,\n ...options.performance,\n memory: {\n ...DEFAULT_OPTIONS.performance.memory,\n ...options.performance?.memory\n },\n stacks: {\n ...DEFAULT_OPTIONS.performance.stacks,\n ...options.performance?.stacks\n }\n }\n }\n}\n","/**\n * 插件运行时共享上下文。\n *\n * 该文件集中维护 MCP 工具、Runtime Bridge 与 CDP Adapter 共用的状态容器,\n * 避免页面、日志和网络缓存分散在各工具模块后出现生命周期不一致。\n */\nimport { createHooks } from 'hookable'\nimport { createRingBuffer } from './shared/ringBuffer'\nimport { DEFAULT_PERFORMANCE_MAX_REPORTS } from './constants'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PageTargetListOptions,\n PageTargetRegistry,\n ResolvedVueMcpNextOptions,\n PerformanceReport,\n PerformanceSession,\n VueMcpNextContext\n} from './types'\n\n/** 一分钟毫秒数,用于声明 runtime 断开记录保留窗口。 */\nconst MINUTE_MS = 60 * 1000\n/** 断开的 runtime 页面只短期保留,避免长期开发会话不断累积历史目标。 */\nconst DISCONNECTED_RUNTIME_TARGET_RETENTION_MS = 5 * MINUTE_MS\n\n/**\n * 判断断开的 runtime 目标是否已经超过保留窗口。\n *\n * 只清理 runtime 历史记录,避免 CDP target 因浏览器临时状态被插件侧误删。\n */\nfunction shouldPruneDisconnectedRuntimeTarget(\n target: PageTarget,\n now: number\n): boolean {\n return (\n target.source === 'runtime' &&\n !target.connected &&\n typeof target.disconnectedAt === 'number' &&\n now - target.disconnectedAt > DISCONNECTED_RUNTIME_TARGET_RETENTION_MS\n )\n}\n\n/**\n * 清理过期的断开 runtime 目标。\n *\n * registry 的公开操作都会调用该函数,让页面列表长期使用时不会无限保留刷新历史。\n */\nfunction pruneDisconnectedRuntimeTargets(\n targets: Map<string, PageTarget>,\n now: number\n): void {\n for (const [pageId, target] of targets) {\n if (shouldPruneDisconnectedRuntimeTarget(target, now)) {\n targets.delete(pageId)\n }\n }\n}\n\n/**\n * 标记页面目标断开。\n *\n * 断开时间只在从 connected 变为 disconnected 时写入,避免重复 disconnect 延长过期记录寿命。\n */\nfunction markTargetDisconnected(target: PageTarget, now: number): PageTarget {\n return {\n ...target,\n connected: false,\n disconnectedAt: target.disconnectedAt ?? now\n }\n}\n\n/**\n * 判断页面目标是否应出现在日常页面列表中。\n *\n * 默认只隐藏断开的 runtime 历史记录;CDP target 是否可连由 CDP 返回值表达,不在这里裁剪。\n */\nfunction shouldListPageTarget(\n target: PageTarget,\n options: PageTargetListOptions\n): boolean {\n return (\n options.includeDisconnected === true ||\n target.source !== 'runtime' ||\n target.connected\n )\n}\n\n/**\n * 断开同一浏览器标签页的旧 runtime 目标。\n *\n * runtime 刷新或 HMR 重连会产生新的 pageId,但同一个 sessionStorage client id 代表同一标签页;\n * 保留旧记录为 disconnected 可以解释历史目标,同时避免 `list_pages` 出现多个可操作的重复页面。\n */\nfunction disconnectPreviousRuntimeClientTarget(\n targets: Map<string, PageTarget>,\n target: PageTarget,\n now: number\n): void {\n if (target.source !== 'runtime' || !target.runtimeClientId) {\n return\n }\n\n for (const [pageId, currentTarget] of targets) {\n if (\n pageId === target.pageId ||\n currentTarget.source !== 'runtime' ||\n currentTarget.runtimeClientId !== target.runtimeClientId ||\n !currentTarget.connected\n ) {\n continue\n }\n\n targets.set(pageId, markTargetDisconnected(currentTarget, now))\n }\n}\n\n/**\n * 创建页面目标注册表。\n *\n * 独立工厂便于单元测试,也避免上下文对象承担过多数据结构细节。\n */\nexport function createPageTargetRegistry(): PageTargetRegistry {\n const targets = new Map<string, PageTarget>()\n\n return {\n upsert(target, now = Date.now()) {\n pruneDisconnectedRuntimeTargets(targets, now)\n disconnectPreviousRuntimeClientTarget(targets, target, now)\n targets.set(target.pageId, target)\n },\n get(pageId) {\n return targets.get(pageId)\n },\n list(options = {}) {\n const now = options.now ?? Date.now()\n pruneDisconnectedRuntimeTargets(targets, now)\n\n return [...targets.values()].filter((target) =>\n shouldListPageTarget(target, options)\n )\n },\n disconnect(pageId, now = Date.now()) {\n pruneDisconnectedRuntimeTargets(targets, now)\n const target = targets.get(pageId)\n\n if (!target) {\n return\n }\n\n targets.set(pageId, markTargetDisconnected(target, now))\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 performanceReports: createRingBuffer<PerformanceReport>(\n DEFAULT_PERFORMANCE_MAX_REPORTS\n ),\n performanceSessions: new Map<string, PerformanceSession>()\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 { registerElementContextTools } from './tools/elementContext'\nimport { registerEvaluateTools } from './tools/evaluate'\nimport { registerNetworkTools } from './tools/network'\nimport { registerPerformanceTools } from './tools/performance'\nimport { registerPageTools } from './tools/pages'\nimport { registerStorageTools } from './tools/storage'\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 registerElementContextTools(server, ctx)\n registerScreenshotTools(server, ctx)\n registerConsoleTools(server, ctx)\n registerEvaluateTools(server, ctx)\n registerNetworkTools(server, ctx)\n registerStorageTools(server, ctx)\n registerPerformanceTools(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","/**\n * MCP 元素上下文工具。\n *\n * 工具只接受用户已经复制的 elementId,不阻塞等待浏览器点击;\n * runtime 在线时返回组件和 DOM 增强信息,离线时仍能解析项目源码或第三方包边界。\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { parseElementId } from '../../shared/elementId'\nimport type { ElementContextResult, VueMcpNextContext } from '../../types'\nimport {\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} from '../routeTools'\n\n/**\n * 注册元素上下文查询工具。\n *\n * 该工具只按用户提供的 elementId 查询上下文,不等待浏览器点击,避免 MCP 请求长期悬挂。\n */\nexport function registerElementContextTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getElementContext,\n {\n description:\n 'Get editable source, Vue component, and DOM context for a copied elementId.',\n inputSchema: {\n elementId: z.string(),\n pageId: z.string().optional()\n }\n },\n async (input) => {\n const runtimeResult = await tryRuntimeElementContext(\n ctx,\n input.elementId,\n input.pageId\n )\n\n if (runtimeResult) {\n return createToolResponse(runtimeResult)\n }\n\n return createToolResponse(createStaticElementContext(input.elementId))\n }\n )\n}\n\n/**\n * 尝试通过浏览器 runtime 获取完整元素上下文。\n *\n * 项目源码和第三方包 ID 可以静态解析;runtime ID 必须依赖浏览器页面,否则无法反查 DOM 引用。\n */\nasync function tryRuntimeElementContext(\n ctx: VueMcpNextContext,\n elementId: string,\n pageId?: string\n): Promise<ElementContextResult | undefined> {\n if (!ctx.rpcServer) {\n return parseElementId(elementId).kind === 'runtime'\n ? createRuntimeUnavailableContext(elementId)\n : undefined\n }\n\n try {\n resolvePageTarget(ctx, pageId)\n } catch (error) {\n const parsed = parseElementId(elementId)\n\n if (parsed.kind === 'project-source' || parsed.kind === 'package') {\n return undefined\n }\n\n return {\n ok: false,\n elementId,\n error: error instanceof Error ? error.message : String(error),\n limitations: ['call list_pages and pass pageId when multiple pages exist']\n }\n }\n\n return (await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.getElementContext({ event, elementId })\n })) as ElementContextResult\n}\n\n/**\n * 创建静态元素上下文。\n *\n * 静态 fallback 不依赖浏览器页面,因此只能返回源码位置或第三方包边界,不能提供 DOM/组件摘要。\n */\nfunction createStaticElementContext(elementId: string): ElementContextResult {\n const parsed = parseElementId(elementId)\n\n if (parsed.kind === 'project-source') {\n return {\n ok: true,\n elementId,\n editable: true,\n codeLocation: {\n file: parsed.file,\n line: parsed.line,\n column: parsed.column\n },\n limitations: ['runtime unavailable, DOM and component context omitted']\n }\n }\n\n if (parsed.kind === 'package') {\n return {\n ok: true,\n elementId,\n editable: false,\n packageLocation: {\n packageName: parsed.packageName,\n entryFile: parsed.entryFile\n },\n limitations: ['third-party package source is not editable from this project']\n }\n }\n\n if (parsed.kind === 'runtime') {\n return createRuntimeUnavailableContext(elementId)\n }\n\n return {\n ok: false,\n elementId,\n error: parsed.reason,\n limitations: ['please provide a copied elementId from the element picker']\n }\n}\n\n/**\n * 创建 runtime 不可用错误。\n *\n * runtime ID 没有静态含义,浏览器断开后必须要求用户重新选择。\n */\nfunction createRuntimeUnavailableContext(elementId: string): ElementContextResult {\n return {\n ok: false,\n elementId,\n error: 'runtime bridge is not connected',\n limitations: ['runtime ids are only valid while the page is connected']\n }\n}\n","/**\n * 元素 ID 共享解析契约。\n *\n * 该文件只处理字符串格式分类,不访问 DOM、runtime 或文件系统;\n * 这样 MCP 在浏览器页面不在线时,仍能基于用户提供的 ID 返回明确边界。\n */\n\nconst PROJECT_SOURCE_ID_PATTERN = /^(.+\\.(?:vue|tsx|jsx|ts|js)):(\\d+):(\\d+)$/\nconst RUNTIME_ID_PATTERN = /^runtime:([A-Za-z0-9_-]+)$/\nconst PACKAGE_ID_PREFIX = 'pkg:'\n\n/**\n * 元素 ID 解析结果。\n *\n * `project-source` 表示可定位到项目源码;`package` 只表达第三方包入口;\n * `runtime` 依赖当前页面生命周期;`invalid` 用于给 AI 返回可解释错误。\n */\nexport type ParsedElementId =\n | {\n readonly kind: 'project-source'\n readonly elementId: string\n readonly file: string\n readonly line: number\n readonly column: number\n }\n | {\n readonly kind: 'package'\n readonly elementId: string\n readonly packageName: string\n readonly entryFile: string\n }\n | {\n readonly kind: 'runtime'\n readonly elementId: string\n readonly runtimeId: string\n }\n | {\n readonly kind: 'invalid'\n readonly elementId: string\n readonly reason: string\n }\n\n/**\n * 解析用户复制给 AI 的元素标识。\n *\n * 该函数只负责格式分类,不判断文件是否存在,也不推断 DOM 是否仍在页面上;\n * 这些上下文需要由 runtime 或 MCP 上层工具补齐。\n */\nexport function parseElementId(elementId: string): ParsedElementId {\n const sourceMatch = PROJECT_SOURCE_ID_PATTERN.exec(elementId)\n\n if (sourceMatch) {\n return {\n kind: 'project-source',\n elementId,\n file: sourceMatch[1],\n line: Number(sourceMatch[2]),\n column: Number(sourceMatch[3])\n }\n }\n\n if (elementId.startsWith(PACKAGE_ID_PREFIX)) {\n return parsePackageElementId(elementId)\n }\n\n const runtimeMatch = RUNTIME_ID_PATTERN.exec(elementId)\n\n if (runtimeMatch) {\n return {\n kind: 'runtime',\n elementId,\n runtimeId: runtimeMatch[1]\n }\n }\n\n return {\n kind: 'invalid',\n elementId,\n reason: 'unsupported elementId format'\n }\n}\n\n/**\n * 解析第三方包元素标识。\n *\n * scope 包需要把前两段作为包名,避免把 `@scope/ui/Button` 错切成 `@scope`;\n * 包级 ID 不返回 `node_modules` 物理路径,避免引导 AI 修改依赖源码。\n */\nfunction parsePackageElementId(elementId: string): ParsedElementId {\n const value = elementId.slice(PACKAGE_ID_PREFIX.length)\n const parts = value.split('/').filter(Boolean)\n\n if (parts.length < 2) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include packageName and entryFile'\n }\n }\n\n const scoped = parts[0]?.startsWith('@')\n const packageName = scoped ? parts.slice(0, 2).join('/') : parts[0]\n const entryFile = parts.slice(scoped ? 2 : 1).join('/')\n\n if (!entryFile) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include entryFile'\n }\n }\n\n return {\n kind: 'package',\n elementId,\n packageName,\n entryFile\n }\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","/**\n * MCP 性能诊断工具。\n *\n * 该文件把 runtime 轻量采样和 CDP 深度采样统一成一组工具,适合分析页面是否卡顿、\n * 是否存在内存增长,以及在调试权限可用时进一步拿到 CPU profile 和 heap snapshot。\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type CDP from 'chrome-remote-interface'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport {\n recordCdpPerformance,\n startCdpPerformanceRecording,\n stopCdpPerformanceRecording,\n takeHeapSnapshot\n} from '../../cdp/cdpPerformance'\nimport type {\n PerformanceReport,\n VueMcpNextContext\n} from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData\n} from '../routeTools'\n\nconst PERFORMANCE_NOT_AVAILABLE_ERROR =\n 'Performance diagnostics are disabled by configuration'\n\nconst activeCdpPerformanceClients = new Map<string, CDP.Client>()\n\ntype PerformanceCdpConnection = NonNullable<\n Awaited<ReturnType<typeof connectCdpForPage>>\n>\n\ninterface PerformanceCdpConnectResult {\n /** CDP 连接成功时返回可直接用于性能采样的客户端。 */\n readonly cdp?: PerformanceCdpConnection\n /** CDP 端口不可达或 target 查询失败时保留原始错误,强制 CDP 模式需要向用户说明原因。 */\n readonly error?: string\n}\n\n/**\n * 注册性能诊断工具。\n *\n * 这组工具同时覆盖无调试权限的 runtime 采样和有 CDP 权限的深度诊断,\n * 让上层只需要关心“是否卡顿”和“能否进一步看 profile”两个层次。\n */\nexport function registerPerformanceTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.recordPerformance,\n {\n description: 'Record a performance sample for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n durationMs: z.number().optional(),\n includeMemory: z.boolean().optional(),\n includeStacks: z.boolean().optional()\n }\n },\n async (input) => handleRecordPerformance(ctx, input as RecordPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.startPerformanceRecording,\n {\n description: 'Start a performance recording session.',\n inputSchema: {\n pageId: z.string().optional(),\n includeMemory: z.boolean().optional(),\n includeStacks: z.boolean().optional()\n }\n },\n async (input) =>\n handleStartPerformanceRecording(ctx, input as StartPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.stopPerformanceRecording,\n {\n description: 'Stop a performance recording session.',\n inputSchema: {\n recordingId: z.string()\n }\n },\n async (input) =>\n handleStopPerformanceRecording(ctx, input as StopPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPerformanceReport,\n {\n description: 'Get cached performance reports and active sessions.',\n inputSchema: {\n pageId: z.string().optional(),\n recordingId: z.string().optional(),\n limit: z.number().optional()\n }\n },\n (input) => handleGetPerformanceReport(ctx, input as GetReportInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.takeHeapSnapshot,\n {\n description: 'Take a heap snapshot with CDP.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n async (input) =>\n handleTakeHeapSnapshot(ctx, input as TakeHeapSnapshotInput)\n )\n}\n\n/**\n * 追加性能报告到缓存。\n *\n * runtime 热推送和 tool 返回可能会同时命中同一份报告,因此这里只做幂等写入,\n * 避免同一个 recordingId 在缓存里重复占位。\n */\nexport function appendPerformanceReport(\n ctx: VueMcpNextContext,\n report: PerformanceReport\n): void {\n if (\n ctx.performanceReports\n .all()\n .some((item) => item.recordingId === report.recordingId)\n ) {\n return\n }\n\n ctx.performanceReports.push(report)\n}\n\n/**\n * 性能采样输入。\n */\ninterface RecordPerformanceInput {\n readonly pageId?: string\n readonly durationMs?: number\n readonly includeMemory?: boolean\n readonly includeStacks?: boolean\n}\n\n/**\n * 性能录制启动输入。\n */\ninterface StartPerformanceInput {\n readonly pageId?: string\n readonly includeMemory?: boolean\n readonly includeStacks?: boolean\n}\n\n/**\n * 性能录制停止输入。\n */\ninterface StopPerformanceInput {\n readonly recordingId: string\n}\n\n/**\n * 性能报告查询输入。\n */\ninterface GetReportInput {\n readonly pageId?: string\n readonly recordingId?: string\n readonly limit?: number\n}\n\n/**\n * heap snapshot 输入。\n */\ninterface TakeHeapSnapshotInput {\n readonly pageId?: string\n}\n\n/**\n * 执行一次性能采样。\n */\nasync function handleRecordPerformance(\n ctx: VueMcpNextContext,\n input: RecordPerformanceInput\n): Promise<CallToolResult> {\n const durationMs = input.durationMs ?? ctx.options.performance.maxDurationMs\n const includeMemory =\n input.includeMemory ?? ctx.options.performance.memory.enabled\n const includeStacks =\n input.includeStacks ?? ctx.options.performance.stacks.enabled\n\n if (ctx.options.performance.mode === 'off') {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n if (ctx.options.performance.mode !== 'hook') {\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (cdp) {\n try {\n const report = await recordCdpPerformance({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n durationMs,\n includeMemory,\n includeStacks,\n saveDir: ctx.options.performance.saveDir\n })\n appendPerformanceReport(ctx, report)\n\n return createToolResponse(toStructuredRecord(report))\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n if (ctx.options.performance.mode === 'cdp') {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP performance collection is unavailable',\n cdpResult.error\n )\n )\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.recordPerformance({\n event,\n durationMs,\n includeMemory,\n includeStacks\n })\n })\n\n if (isPerformanceReport(result)) {\n appendPerformanceReport(ctx, result)\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n}\n\n/**\n * 开始一次性能录制。\n */\nasync function handleStartPerformanceRecording(\n ctx: VueMcpNextContext,\n input: StartPerformanceInput\n): Promise<CallToolResult> {\n const includeMemory =\n input.includeMemory ?? ctx.options.performance.memory.enabled\n const includeStacks =\n input.includeStacks ?? ctx.options.performance.stacks.enabled\n\n if (ctx.options.performance.mode === 'off') {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n if (ctx.options.performance.mode !== 'hook') {\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (cdp) {\n try {\n const session = await startCdpPerformanceRecording({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n includeMemory,\n includeStacks,\n saveDir: ctx.options.performance.saveDir\n })\n\n ctx.performanceSessions.set(session.recordingId, {\n recordingId: session.recordingId,\n pageId: session.pageId,\n source: 'cdp',\n startedAt: session.startedAt,\n includeMemory,\n includeStacks,\n mode: ctx.options.performance.mode\n })\n activeCdpPerformanceClients.set(session.recordingId, cdp.client)\n\n return createToolResponse(\n toStructuredRecord({\n ...session,\n source: 'cdp'\n })\n )\n } catch (error) {\n await closeCdpClient(cdp.client)\n return createToolError(\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n\n if (ctx.options.performance.mode === 'cdp') {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP performance collection is unavailable',\n cdpResult.error\n )\n )\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.startPerformanceRecording({\n event,\n includeMemory,\n includeStacks\n })\n })\n\n if (isPerformanceStartResult(result)) {\n ctx.performanceSessions.set(result.recordingId, {\n recordingId: result.recordingId,\n pageId: input.pageId ?? 'runtime',\n source: 'hook',\n startedAt: result.startedAt,\n includeMemory,\n includeStacks,\n mode: ctx.options.performance.mode\n })\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n}\n\n/**\n * 结束一次性能录制。\n */\nasync function handleStopPerformanceRecording(\n ctx: VueMcpNextContext,\n input: StopPerformanceInput\n): Promise<CallToolResult> {\n const session = ctx.performanceSessions.get(input.recordingId)\n\n if (!session) {\n return createToolError(`Performance recording not found: ${input.recordingId}`)\n }\n\n try {\n if (session.source === 'cdp') {\n const client = activeCdpPerformanceClients.get(input.recordingId)\n\n if (!client) {\n return createToolError(\n `CDP client not found for recording: ${input.recordingId}`\n )\n }\n\n const report = await stopCdpPerformanceRecording({\n client,\n session\n })\n appendPerformanceReport(ctx, report)\n\n return createToolResponse(toStructuredRecord(report))\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.stopPerformanceRecording({\n event,\n recordingId: input.recordingId\n })\n })\n\n if (isPerformanceReport(result)) {\n appendPerformanceReport(ctx, result)\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n } finally {\n ctx.performanceSessions.delete(input.recordingId)\n const client = activeCdpPerformanceClients.get(input.recordingId)\n\n if (client) {\n activeCdpPerformanceClients.delete(input.recordingId)\n await closeCdpClient(client)\n }\n }\n}\n\n/**\n * 查询缓存中的性能报告。\n */\nfunction handleGetPerformanceReport(\n ctx: VueMcpNextContext,\n input: GetReportInput\n): CallToolResult {\n const reports = ctx.performanceReports\n .all()\n .filter((report) => !input.pageId || report.pageId === input.pageId)\n .filter(\n (report) => !input.recordingId || report.recordingId === input.recordingId\n )\n const limit = input.limit ?? reports.length\n\n return createToolResponse(toStructuredRecord({\n report: reports.at(-1) ?? null,\n reports: reports.slice(-limit),\n sessions: [...ctx.performanceSessions.values()].filter(\n (session) =>\n (!input.pageId || session.pageId === input.pageId) &&\n (!input.recordingId || session.recordingId === input.recordingId)\n )\n }))\n}\n\n/**\n * 采集 heap snapshot。\n */\nasync function handleTakeHeapSnapshot(\n ctx: VueMcpNextContext,\n input: TakeHeapSnapshotInput\n): Promise<CallToolResult> {\n if (\n ctx.options.performance.mode === 'off' ||\n ctx.options.performance.mode === 'hook'\n ) {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (!cdp) {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP heap snapshot is unavailable',\n cdpResult.error\n )\n )\n }\n\n try {\n return createToolResponse(\n toStructuredRecord(await takeHeapSnapshot({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n saveDir: ctx.options.performance.saveDir\n }))\n )\n } finally {\n await closeCdpClient(cdp.client)\n }\n}\n\n/**\n * 尝试建立性能诊断专用 CDP 连接。\n *\n * `auto` 模式的核心承诺是“有调试权限走 CDP,没有调试权限退回 Runtime Hook”,\n * 因此 CDP discovery 的网络失败不能直接打断性能工具;只有强制 CDP 的工具分支才会把错误返回给用户。\n */\nasync function connectPerformanceCdp(\n ctx: VueMcpNextContext,\n pageId?: string\n): Promise<PerformanceCdpConnectResult> {\n try {\n return { cdp: await connectCdpForPage(ctx, pageId) }\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 格式化 CDP 不可用错误。\n *\n * 强制 CDP 模式需要暴露底层原因方便用户检查 `--remote-debugging-port`,\n * 但普通不可用场景仍保持稳定的工具错误前缀,避免调用方只靠文案判断时被破坏。\n */\nfunction formatCdpUnavailableError(message: string, reason?: string): string {\n if (!reason) {\n return message\n }\n\n return `${message}: ${reason}`\n}\n\n/**\n * 判断 runtime 回包是否为性能报告。\n */\nfunction isPerformanceReport(value: unknown): value is PerformanceReport {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const report = value as Partial<PerformanceReport>\n\n return (\n typeof report.recordingId === 'string' &&\n typeof report.pageId === 'string' &&\n (report.source === 'hook' || report.source === 'cdp') &&\n typeof report.startedAt === 'number' &&\n typeof report.endedAt === 'number' &&\n typeof report.durationMs === 'number' &&\n Boolean(report.summary) &&\n Array.isArray(report.longTasks) &&\n Array.isArray(report.limitations)\n )\n}\n\n/**\n * 判断 runtime 回包是否为录制启动结果。\n */\nfunction isPerformanceStartResult(\n value: unknown\n): value is { recordingId: string; startedAt: number } {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const result = value as Partial<{ recordingId: string; startedAt: number }>\n\n return (\n typeof result.recordingId === 'string' &&\n typeof result.startedAt === 'number'\n )\n}\n\n/**\n * 判断值是否为可直接返回给 MCP 的普通对象。\n */\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * 将任意对象收敛为 MCP 需要的普通 record。\n */\nfunction toStructuredRecord(value: unknown): Record<string, unknown> {\n if (isPlainRecord(value)) {\n return value\n }\n\n return {}\n}\n","/**\n * 性能报告摘要计算。\n *\n * 这个文件只保留纯数据归纳逻辑,不依赖浏览器 API 或 CDP client,便于 runtime 和 CDP 两条路径共享同一口径。\n */\nimport { DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS } from '../constants'\nimport type {\n LongTaskRecord,\n MemorySample,\n MemorySummary,\n PerformanceSummary,\n StackFrameSummary,\n StackSummary\n} from '../types'\n\n/**\n * 计算性能摘要。\n *\n * 该摘要面向快速判断页面是否明显卡顿,不追求把所有原始信号都塞进结果里。\n */\nexport function buildPerformanceSummary(input: {\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n}): PerformanceSummary {\n const memory = buildMemorySummary(input.memorySamples)\n const blockedTimeMs = input.longTasks.reduce((total, task) => {\n return (\n total +\n Math.max(0, task.durationMs - DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS)\n )\n }, 0)\n const longTaskCount = input.longTasks.length\n const durations = input.longTasks.map((task) => task.durationMs)\n const maxTaskDurationMs = durations.length ? Math.max(...durations) : 0\n const averageTaskDurationMs = durations.length\n ? Math.round(\n durations.reduce((total, duration) => total + duration, 0) /\n durations.length\n )\n : undefined\n const suspectedJank =\n blockedTimeMs > 0 || memory.trend === 'growing' || longTaskCount > 0\n const severity = resolveSeverity({\n blockedTimeMs,\n longTaskCount,\n memoryTrend: memory.trend\n })\n\n return {\n blockedTimeMs,\n longTaskCount,\n maxTaskDurationMs,\n averageTaskDurationMs,\n suspectedJank,\n severity\n }\n}\n\n/**\n * 计算内存趋势。\n *\n * 只比较首尾和峰值,不推断对象引用关系,这样 runtime-only 路径也能给出稳定结论。\n */\nexport function buildMemorySummary(samples: MemorySample[]): MemorySummary {\n const first = samples[0]?.usedJSHeapSize\n const last = samples.at(-1)?.usedJSHeapSize\n const peak = samples.reduce((currentPeak, sample) => {\n if (typeof sample.usedJSHeapSize !== 'number') {\n return currentPeak\n }\n\n return Math.max(currentPeak, sample.usedJSHeapSize)\n }, 0)\n\n const trend = resolveMemoryTrend(first, last)\n\n return {\n samples,\n initialUsedJSHeapSize: first,\n finalUsedJSHeapSize: last,\n peakUsedJSHeapSize: peak || undefined,\n deltaUsedJSHeapSize:\n typeof first === 'number' && typeof last === 'number'\n ? last - first\n : undefined,\n trend\n }\n}\n\n/**\n * 计算堆栈摘要。\n *\n * 该函数只做排序和裁剪,不直接理解 CPU profile 或错误对象,方便 CDP 和 runtime 传入不同来源的帧数据。\n */\nexport function buildStackSummary(\n frames: StackFrameSummary[],\n options: { rawProfilePath?: string; limitation?: string } = {}\n): StackSummary {\n return {\n topFrames: [...frames].sort(sortByHotness).slice(0, 10),\n rawProfilePath: options.rawProfilePath,\n limitation: options.limitation\n }\n}\n\n/**\n * 根据卡顿指标判断严重程度。\n *\n * 这个分级只用于调试报告的阅读提示,不代表生产级告警阈值。\n */\nfunction resolveSeverity(input: {\n blockedTimeMs: number\n longTaskCount: number\n memoryTrend: MemorySummary['trend']\n}): PerformanceSummary['severity'] {\n if (input.blockedTimeMs >= 1000 || input.longTaskCount >= 10) {\n return 'critical'\n }\n\n if (input.blockedTimeMs > 0 || input.memoryTrend === 'growing') {\n return 'warning'\n }\n\n return 'ok'\n}\n\n/**\n * 根据首尾内存采样判断趋势。\n *\n * 只要存在明显上升就视为 growing,避免 runtime 路径因单次抖动而过度乐观。\n */\nfunction resolveMemoryTrend(\n first: number | undefined,\n last: number | undefined\n): MemorySummary['trend'] {\n if (typeof first !== 'number' || typeof last !== 'number') {\n return 'unknown'\n }\n\n if (last > first) {\n return 'growing'\n }\n\n return 'stable'\n}\n\n/**\n * 按热点程度给堆栈帧排序。\n *\n * 优先比较总耗时,再比较自身耗时和命中次数,保证摘要更偏向真正的热点函数。\n */\nfunction sortByHotness(\n left: StackFrameSummary,\n right: StackFrameSummary\n): number {\n return compareNumber(right.totalTimeMs, left.totalTimeMs)\n || compareNumber(right.selfTimeMs, left.selfTimeMs)\n || compareNumber(right.hitCount, left.hitCount)\n}\n\n/**\n * 比较可选数值。\n *\n * 空值统一排后,方便摘要维持稳定排序。\n */\nfunction compareNumber(left?: number, right?: number): number {\n return (left ?? -1) - (right ?? -1)\n}\n","/**\n * 性能产物落盘 helper。\n *\n * CDP 侧原始 profile 和 heap snapshot 都可能很大,因此需要统一把它们写进项目目录并返回路径型结果。\n */\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { relative, resolve } from 'node:path'\nimport { nanoid } from 'nanoid'\nimport type { PerformanceArtifact } from '../types'\n\n/**\n * 落盘性能产物的输入。\n *\n * helper 只处理文件路径、字节大小和写入,不关心调用方是 CPU profile 还是 heap snapshot。\n */\nexport interface WritePerformanceArtifactOptions {\n /** 项目根目录。 */\n readonly root?: string\n /** 保存目录,相对路径按项目根目录解析。 */\n readonly saveDir: string\n /** 文件名,调用方负责决定扩展名和语义前缀。 */\n readonly fileName: string\n /** 产物类型。 */\n readonly kind: PerformanceArtifact['kind']\n /** 原始数据。 */\n readonly data: string | Buffer\n}\n\n/**\n * 把性能产物写入磁盘。\n *\n * 这个 helper 会创建保存目录、写入数据,并返回路径型 artifact,避免大对象直接进入 MCP 响应。\n */\nexport async function writePerformanceArtifact(\n options: WritePerformanceArtifactOptions\n): Promise<PerformanceArtifact> {\n const root = resolve(options.root ?? process.cwd())\n const dir = resolveOutputDirectory(root, options.saveDir)\n const path = resolve(dir, createSafeFileName(options.fileName))\n const data = typeof options.data === 'string' ? Buffer.from(options.data) : options.data\n\n await mkdir(dir, { recursive: true })\n await writeFile(path, data)\n\n return {\n kind: options.kind,\n path,\n relativePath: relative(root, path),\n byteLength: data.byteLength,\n source: 'cdp'\n }\n}\n\n/**\n * 解析性能产物保存目录。\n *\n * 相对路径按项目根目录解析,绝对路径则原样保留,这样用户可以把重产物单独放到外部目录。\n */\nfunction resolveOutputDirectory(root: string, saveDir: string): string {\n return resolve(root, saveDir)\n}\n\n/**\n * 生成安全文件名。\n *\n * 文件名允许调用方提供前缀,但会补一个短随机后缀,避免同一毫秒内重复写入发生冲突。\n */\nfunction createSafeFileName(fileName: string): string {\n const trimmed = fileName.trim()\n\n if (!trimmed) {\n return `${String(Date.now())}-${nanoid()}`\n }\n\n const suffix = nanoid(6)\n const dotIndex = trimmed.lastIndexOf('.')\n\n if (dotIndex === -1) {\n return `${trimmed}-${suffix}`\n }\n\n const base = trimmed.slice(0, dotIndex)\n const extension = trimmed.slice(dotIndex)\n\n return `${base}-${suffix}${extension}`\n}\n","/**\n * CDP 性能采集。\n *\n * 该文件只处理浏览器调试协议可见的性能指标、CPU profile 和 heap snapshot,不承载 runtime 降级逻辑。\n */\nimport type CDP from 'chrome-remote-interface'\nimport {\n buildMemorySummary,\n buildPerformanceSummary,\n buildStackSummary\n} from '../performance/summary'\nimport { writePerformanceArtifact } from '../performance/output'\nimport type {\n LongTaskRecord,\n MemorySample,\n PerformanceArtifact,\n PerformanceReport,\n StackFrameSummary\n} from '../types'\n\n/**\n * CDP 性能采集参数。\n */\nexport interface CdpPerformanceOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 当前页面 id,用于输出产物命名和报告聚合。 */\n readonly pageId: string\n /** 采集窗口时长。 */\n readonly durationMs: number\n /** 是否采集内存。 */\n readonly includeMemory: boolean\n /** 是否采集可定位堆栈。 */\n readonly includeStacks: boolean\n /** 保存原始 profile 的目录,默认 `.vite-mcp/performance`。 */\n readonly saveDir?: string\n}\n\n/**\n * CDP 性能启动参数。\n *\n * start 阶段不需要采样窗口时长,只负责打开 profiler 并留下会话信息。\n */\nexport type CdpPerformanceStartOptions = Omit<CdpPerformanceOptions, 'durationMs'>\n\n/**\n * CDP 性能会话信息。\n *\n * 交互式录制需要在 start/stop 两次工具调用之间保持会话元数据,\n * 但不把裸 client 暴露给上层的 structuredContent。\n */\nexport interface CdpPerformanceSession {\n /** 录制 id。 */\n readonly recordingId: string\n /** 页面 id。 */\n readonly pageId: string\n /** 开始时间。 */\n readonly startedAt: number\n /** 是否采集内存。 */\n readonly includeMemory: boolean\n /** 是否采集堆栈。 */\n readonly includeStacks: boolean\n /** 保存目录。 */\n readonly saveDir?: string\n}\n\n/**\n * Heap snapshot 采集参数。\n */\nexport interface HeapSnapshotOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 当前页面 id,用于输出产物命名。 */\n readonly pageId: string\n /** 保存 heap snapshot 的目录。 */\n readonly saveDir: string\n}\n\n/**\n * CDP 的最小性能 metric 结构。\n */\ninterface CdpMetric {\n /** metric 名称。 */\n readonly name: string\n /** metric 值。 */\n readonly value: number\n}\n\n/**\n * CDP 性能 metric 返回值。\n */\ninterface CdpMetricsResult {\n readonly metrics: CdpMetric[]\n}\n\n/**\n * CDP CPU profile 结构。\n */\ninterface CdpCpuProfile {\n readonly nodes?: CdpCpuProfileNode[]\n readonly samples?: number[]\n readonly timeDeltas?: number[]\n}\n\n/**\n * CDP CPU profile stop 返回值。\n */\ninterface CdpProfileResult {\n readonly profile: CdpCpuProfile\n}\n\n/**\n * CPU profile 节点。\n */\ninterface CdpCpuProfileNode {\n readonly id: number\n readonly callFrame: {\n readonly functionName: string\n readonly url?: string\n readonly lineNumber?: number\n readonly columnNumber?: number\n }\n readonly hitCount?: number\n}\n\n/**\n * 使用 CDP 采集性能报告。\n */\nexport async function recordCdpPerformance(\n options: CdpPerformanceOptions\n): Promise<PerformanceReport> {\n const session = await startCdpPerformanceRecording(options)\n await waitForDuration(options.durationMs)\n return stopCdpPerformanceRecording({\n client: options.client,\n session\n })\n}\n\n/**\n * 开始一次 CDP 性能录制。\n */\nexport async function startCdpPerformanceRecording(\n options: CdpPerformanceStartOptions\n): Promise<CdpPerformanceSession> {\n await options.client.Performance.enable()\n await options.client.Profiler.enable()\n await options.client.Profiler.start()\n\n return {\n recordingId: createRecordingId(options.pageId),\n pageId: options.pageId,\n startedAt: Date.now(),\n includeMemory: options.includeMemory,\n includeStacks: options.includeStacks,\n saveDir: options.saveDir\n }\n}\n\n/**\n * 停止一次 CDP 性能录制并生成报告。\n */\nexport async function stopCdpPerformanceRecording(options: {\n readonly client: CDP.Client\n readonly session: CdpPerformanceSession\n}): Promise<PerformanceReport> {\n const endedAt = Date.now()\n const [metricsResult, profileResult] = await Promise.all([\n options.client.Performance.getMetrics() as Promise<CdpMetricsResult>,\n options.client.Profiler.stop() as Promise<CdpProfileResult>\n ])\n\n const metrics = toMetricMap(metricsResult.metrics)\n const longTasks = toLongTaskRecords(metrics)\n const memorySamples = options.session.includeMemory\n ? [toMemorySample(metrics)]\n : []\n const memory = options.session.includeMemory\n ? buildMemorySummary(memorySamples)\n : undefined\n const stacks = options.session.includeStacks\n ? buildStackSummary(aggregateCpuProfile(profileResult.profile))\n : undefined\n const artifact = await writeCpuProfileArtifact(\n {\n pageId: options.session.pageId,\n saveDir: options.session.saveDir\n },\n profileResult.profile\n )\n const report: PerformanceReport = {\n recordingId: options.session.recordingId,\n pageId: options.session.pageId,\n source: 'cdp',\n startedAt: options.session.startedAt,\n endedAt,\n durationMs: endedAt - options.session.startedAt,\n summary: buildPerformanceSummary({\n longTasks,\n memorySamples\n }),\n longTasks,\n memory,\n stacks,\n artifacts: [artifact],\n limitations: [\n 'CDP path returns sampled CPU profile data, not a full instruction trace'\n ]\n }\n\n return report\n}\n\n/**\n * 采集 heap snapshot 并返回路径型产物。\n */\nexport async function takeHeapSnapshot(\n options: HeapSnapshotOptions\n): Promise<PerformanceArtifact> {\n const chunks: string[] = []\n\n await options.client.HeapProfiler.enable()\n options.client.HeapProfiler.addHeapSnapshotChunk((event) => {\n const payload = event as { chunk?: string }\n if (payload.chunk) {\n chunks.push(payload.chunk)\n }\n })\n\n await options.client.HeapProfiler.takeHeapSnapshot({\n reportProgress: false\n })\n\n const artifact = await writePerformanceArtifact({\n root: process.cwd(),\n saveDir: options.saveDir,\n fileName: `${options.pageId}-heap-snapshot.heapsnapshot`,\n kind: 'heap-snapshot',\n data: Buffer.from(chunks.join(''))\n })\n\n return artifact\n}\n\n/**\n * 创建录制 id。\n */\nfunction createRecordingId(pageId: string): string {\n return `cdp-${pageId}-${String(Date.now())}`\n}\n\n/**\n * 等待指定时长。\n */\nfunction waitForDuration(durationMs: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve()\n }, durationMs)\n })\n}\n\n/**\n * 将 metrics 转成 map。\n */\nfunction toMetricMap(metrics: CdpMetric[]): Map<string, number> {\n return new Map(metrics.map((metric) => [metric.name, metric.value]))\n}\n\n/**\n * 将 CDP metrics 归一成 long task 记录。\n */\nfunction toLongTaskRecords(metrics: Map<string, number>): LongTaskRecord[] {\n const taskDuration = metrics.get('TaskDuration') ?? 0\n\n if (taskDuration <= 0) {\n return []\n }\n\n return [\n {\n startTime: 0,\n durationMs: taskDuration,\n name: 'TaskDuration',\n source: 'cpu-profile'\n }\n ]\n}\n\n/**\n * 将 metrics 归一成内存采样。\n */\nfunction toMemorySample(metrics: Map<string, number>): MemorySample {\n return {\n timestamp: Date.now(),\n usedJSHeapSize: metrics.get('JSHeapUsedSize'),\n totalJSHeapSize: metrics.get('JSHeapTotalSize'),\n jsHeapSizeLimit: metrics.get('JSHeapSizeLimit')\n }\n}\n\n/**\n * 聚合 CPU profile 热点。\n */\nfunction aggregateCpuProfile(profile: CdpCpuProfile): StackFrameSummary[] {\n const nodes = profile.nodes ?? []\n const nodeMap = new Map<number, AggregatedFrame>()\n const nodeIndex = new Map<number, CdpCpuProfileNode>()\n\n nodes.forEach((node) => nodeIndex.set(node.id, node))\n ;(profile.samples ?? []).forEach((nodeId, index) => {\n const node = nodeIndex.get(nodeId)\n if (!node) {\n return\n }\n\n const delta = profile.timeDeltas?.[index] ?? 0\n const current = nodeMap.get(nodeId) ?? {\n functionName: node.callFrame.functionName || '<anonymous>',\n url: node.callFrame.url,\n lineNumber: node.callFrame.lineNumber,\n columnNumber: node.callFrame.columnNumber,\n selfTimeMs: 0,\n totalTimeMs: 0,\n hitCount: 0\n }\n\n nodeMap.set(nodeId, {\n ...current,\n selfTimeMs: current.selfTimeMs + delta,\n totalTimeMs: current.totalTimeMs + delta,\n hitCount: current.hitCount + 1\n })\n })\n\n return [...nodeMap.values()]\n}\n\n/**\n * CDP 热点帧的内部累加结构。\n */\ninterface AggregatedFrame extends StackFrameSummary {\n selfTimeMs: number\n totalTimeMs: number\n hitCount: number\n}\n\n/**\n * 将 CPU profile 写成原始文件。\n */\nasync function writeCpuProfileArtifact(\n options: {\n readonly pageId: string\n readonly saveDir?: string\n },\n profile: CdpCpuProfile\n): Promise<PerformanceArtifact> {\n return writePerformanceArtifact({\n root: process.cwd(),\n saveDir: options.saveDir ?? '.vite-mcp/performance',\n fileName: `${options.pageId}-cpu-profile.cpuprofile`,\n kind: 'cpu-profile',\n data: Buffer.from(JSON.stringify(profile, null, 2))\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 inputSchema: {\n includeDisconnected: z.boolean().optional()\n }\n },\n async (input) => {\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 includeDisconnected: input.includeDisconnected\n }),\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","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { createCdpStorageAdapter } from '../../cdp/cdpStorage'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type {\n RuntimeStorageRequest,\n StorageAction,\n StorageScope,\n VueMcpNextContext\n} from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} from '../routeTools'\n\n/**\n * 注册浏览器存储相关 MCP 工具。\n *\n * 存储能力同时触及页面同源数据和浏览器级 Cookie,必须单独成组以便清晰表达 runtime 同源边界、\n * CDP 浏览器级能力,以及 HttpOnly Cookie 的只读/不可见限制。\n */\nexport function registerStorageTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {\n description: 'List same-origin storage and CDP cookies when available.',\n inputSchema: {\n pageId: z.string().optional()\n },\n action: 'list',\n handler: (input) => handleListStorage(ctx, input.pageId)\n })\n registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {\n description: 'Read one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'get',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'get' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {\n description: 'Write one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'set',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'set' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {\n description: 'Delete one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'delete',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'delete' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {\n description: 'Clear one storage scope.',\n inputSchema: createStorageInputSchema(),\n action: 'clear',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'clear' })\n })\n}\n\ninterface StorageToolInput {\n readonly pageId?: string\n readonly action: StorageAction\n readonly scope?: StorageScope\n readonly key?: string\n readonly value?: string\n readonly databaseName?: string\n readonly objectStoreName?: string\n readonly indexName?: string\n readonly cookie?: RuntimeStorageRequest['cookie']\n}\n\nfunction registerStorageTool<TInput extends z.ZodRawShape>(\n server: McpServer,\n name: string,\n options: {\n readonly description: string\n readonly inputSchema: TInput\n readonly action: StorageAction\n readonly handler: (input: z.infer<z.ZodObject<TInput>>) => Promise<unknown>\n }\n): void {\n server.registerTool(\n name,\n {\n description: options.description,\n inputSchema: options.inputSchema\n },\n (async (input: unknown) =>\n options.handler(\n input as z.infer<z.ZodObject<TInput>>\n )) as never\n )\n}\n\nfunction createStorageInputSchema() {\n return {\n pageId: z.string().optional(),\n scope: z\n .enum(['localStorage', 'sessionStorage', 'indexedDB', 'cookie'])\n .optional(),\n key: z.string().optional(),\n value: z.string().optional(),\n databaseName: z.string().optional(),\n objectStoreName: z.string().optional(),\n indexName: z.string().optional(),\n cookie: z\n .object({\n name: z.string(),\n value: z.string().optional(),\n domain: z.string().optional(),\n path: z.string().optional(),\n url: z.string().optional(),\n httpOnly: z.boolean().optional(),\n secure: z.boolean().optional(),\n sameSite: z.enum(['strict', 'lax', 'none']).optional(),\n expires: z.number().optional()\n })\n .optional()\n }\n}\n\n/**\n * 汇总当前页面可访问的同源存储,并附加 Cookie 概览。\n *\n * list_storage 面向排查场景,默认返回整体概览比单 scope 更符合使用预期;Cookie 在 CDP 可用时\n * 使用浏览器级查询,否则回退到 document.cookie 可见的同源 Cookie。\n */\nasync function handleListStorage(\n ctx: VueMcpNextContext,\n pageId?: string\n) {\n let baseRequest: RuntimeStorageRequest\n\n try {\n baseRequest = createStorageRequest(ctx, {\n pageId,\n action: 'list',\n scope: 'localStorage'\n })\n } catch (error) {\n return createToolError(error instanceof Error ? error.message : String(error))\n }\n\n const [localStorage, sessionStorage, indexedDB] = await Promise.all([\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'localStorage' }),\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'sessionStorage' }),\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'indexedDB' })\n ])\n const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId)\n\n return createToolResponse({\n ok: true,\n origin: baseRequest.origin,\n localStorage: extractStorageData(localStorage),\n sessionStorage: extractStorageData(sessionStorage),\n indexedDB: extractStorageData(indexedDB),\n cookie\n })\n}\n\n/**\n * 执行单个存储读写动作,并按 scope 选择 CDP 或运行时桥接。\n *\n * Cookie 属于浏览器级资源,必须走 CDP;IndexedDB 写入仍保留运行时桥接作为兜底,因为 CDP\n * 不提供通用的对象写入接口。\n */\nasync function handleStorageAction(\n ctx: VueMcpNextContext,\n input: StorageToolInput\n) {\n let request: RuntimeStorageRequest\n\n try {\n request = createStorageRequest(ctx, input)\n } catch (error) {\n return createToolError(error instanceof Error ? error.message : String(error))\n }\n\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (cdp && shouldUseCdpStorage(request)) {\n try {\n const result = await createCdpStorageAdapter(cdp.client).manageStorage(\n request\n )\n\n return createToolResponse(result)\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const result = await requestRuntimeStorage(ctx, request)\n\n return createToolResponse(result)\n}\n\n/**\n * 通过页面运行时桥接访问同源存储。\n *\n * 该路径继承浏览器同源策略,适合 localStorage、sessionStorage 以及 IndexedDB 的页面级操作。\n */\nasync function requestRuntimeStorage(\n ctx: VueMcpNextContext,\n request: RuntimeStorageRequest\n): Promise<unknown> {\n return requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.manageStorage({\n ...request,\n event\n })\n })\n}\n\n/**\n * 读取 Cookie 概览。\n *\n * CDP 可用时返回浏览器级 Cookie;否则回退到 runtime 可见 Cookie,避免无 CDP 环境下丢失\n * 当前页面同源 Cookie 的基础排查能力。\n */\nasync function listCookiesIfCdpAvailable(\n ctx: VueMcpNextContext,\n request: RuntimeStorageRequest,\n pageId?: string\n): Promise<unknown> {\n if (!hasCdpConfig(ctx)) {\n return extractStorageData(\n await requestRuntimeStorage(ctx, { ...request, scope: 'cookie' })\n )\n }\n\n const cdp = await connectCdpForPage(ctx, pageId)\n\n if (!cdp) {\n return extractStorageData(\n await requestRuntimeStorage(ctx, { ...request, scope: 'cookie' })\n )\n }\n\n try {\n const result = await createCdpStorageAdapter(cdp.client).manageStorage({\n ...request,\n scope: 'cookie'\n })\n\n return extractStorageData(result)\n } finally {\n await closeCdpClient(cdp.client)\n }\n}\n\n/**\n * 提取存储适配器的业务数据。\n *\n * MCP 工具对外只需要展示实际存储内容;保留原始结果作为异常形态兜底,便于测试和调试定位。\n */\nfunction extractStorageData(result: unknown): unknown {\n if (!isStorageResultRecord(result)) {\n return result\n }\n\n return result.data ?? result\n}\n\n/**\n * 判断结果是否符合存储适配器的基础结构。\n *\n * 这里仅检查 ok 字段,避免对不同 scope 的 data 形态做过度约束。\n */\nfunction isStorageResultRecord(\n value: unknown\n): value is { readonly data?: unknown } {\n return typeof value === 'object' && value !== null && 'ok' in value\n}\n\n/**\n * 判断单次存储操作是否应交给 CDP。\n *\n * Cookie 需要浏览器级权限,始终走 CDP;IndexedDB 属于页面同源存储,统一走 runtime 桥接,\n * 避免不同浏览器版本的 CDP IndexedDB 协议差异导致读取或删除卡住。\n */\nfunction shouldUseCdpStorage(request: RuntimeStorageRequest): boolean {\n return request.scope === 'cookie'\n}\n\nfunction createStorageRequest(\n ctx: VueMcpNextContext,\n input: StorageToolInput\n): RuntimeStorageRequest {\n const page = resolvePageTarget(ctx, input.pageId)\n const origin = new URL(page.url).origin\n\n return {\n event: '',\n pageId: page.pageId,\n origin,\n action: input.action,\n scope: normalizeScope(input.scope),\n key: input.key,\n value: input.value,\n databaseName: input.databaseName,\n objectStoreName: input.objectStoreName,\n indexName: input.indexName,\n cookie: input.cookie\n }\n}\n\nfunction normalizeScope(scope?: StorageScope): StorageScope {\n return scope ?? 'localStorage'\n}\n\nfunction hasCdpConfig(ctx: VueMcpNextContext): boolean {\n return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint)\n}\n","import type CDP from 'chrome-remote-interface'\nimport type { RuntimeStorageRequest, RuntimeStorageResult } from '../types'\n\n/**\n * CDP 存储适配器。\n *\n * Cookie 和部分 IndexedDB 能力需要浏览器协议权限;单独收敛在这里可以避免 MCP 工具层\n * 直接拼协议参数,也让 HttpOnly 删除限制集中审查。\n */\n\n/** CDP 存储适配器实例。 */\nexport interface CdpStorageAdapter {\n /** 根据统一存储请求调用 CDP 存储协议。 */\n manageStorage(request: RuntimeStorageRequest): Promise<RuntimeStorageResult>\n}\n\n/**\n * 创建 CDP 存储适配器。\n *\n * 调用方负责连接和关闭 CDP client,本适配器只执行单次存储操作。\n */\nexport function createCdpStorageAdapter(client: CDP.Client): CdpStorageAdapter {\n return {\n async manageStorage(request) {\n try {\n return await manageCdpStorage(client, request)\n } catch (error) {\n return createCdpStorageError(\n request,\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n }\n}\n\nasync function manageCdpStorage(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.scope === 'cookie') {\n return manageCdpCookies(client, request)\n }\n\n if (request.scope === 'indexedDB') {\n return manageCdpIndexedDb(client, request)\n }\n\n return manageCdpDomStorage(client, request)\n}\n\nasync function manageCdpCookies(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.action === 'list' || request.action === 'get') {\n const result = await client.Storage.getCookies()\n const cookies = result.cookies.filter((cookie) =>\n isCookieInOrigin(cookie, request.origin)\n )\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n cookies:\n request.action === 'get' && request.cookie?.name\n ? cookies.filter((cookie) => cookie.name === request.cookie?.name)\n : cookies\n })\n }\n\n if (request.action === 'set') {\n if (!request.cookie?.name) {\n throw new Error('Cookie name is required for set operation')\n }\n\n await client.Storage.setCookies({\n cookies: [\n {\n name: request.cookie.name,\n value: request.cookie.value ?? request.value ?? '',\n url: request.cookie.url ?? request.origin,\n domain: request.cookie.domain,\n path: request.cookie.path,\n httpOnly: request.cookie.httpOnly,\n secure: request.cookie.secure,\n sameSite: normalizeCookieSameSite(request.cookie.sameSite),\n expires: request.cookie.expires\n }\n ]\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n const result = await client.Storage.getCookies()\n const cookies = result.cookies.filter((cookie) =>\n isCookieInOrigin(cookie, request.origin)\n )\n const candidates =\n request.action === 'delete' && request.cookie?.name\n ? cookies.filter((cookie) => cookie.name === request.cookie?.name)\n : cookies\n const deletable = candidates.filter((cookie) => !cookie.httpOnly)\n const skippedHttpOnlyCount = candidates.length - deletable.length\n\n for (const cookie of deletable) {\n await client.Network.deleteCookies({\n name: cookie.name,\n domain: cookie.domain,\n path: cookie.path\n })\n }\n\n return createCdpStorageSuccess(request, {\n deletedCount: deletable.length,\n skippedHttpOnlyCount\n })\n}\n\nasync function manageCdpDomStorage(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n const storageId = {\n securityOrigin: request.origin,\n isLocalStorage: request.scope === 'localStorage'\n }\n\n if (request.action === 'list') {\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n entries: result.entries.map(([key, value]) => ({ key, value }))\n })\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n const entry = result.entries.find(([key]) => key === request.key)\n\n return createCdpStorageSuccess(request, {\n key: request.key,\n value: entry?.[1] ?? null\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n await client.DOMStorage.setDOMStorageItem({\n storageId,\n key: request.key,\n value: request.value ?? ''\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n await client.DOMStorage.removeDOMStorageItem({\n storageId,\n key: request.key\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n\n for (const [key] of result.entries) {\n await client.DOMStorage.removeDOMStorageItem({ storageId, key })\n }\n\n return createCdpStorageSuccess(request, { deletedCount: result.entries.length })\n}\n\nasync function manageCdpIndexedDb(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.action === 'list') {\n const result = await client.IndexedDB.requestDatabaseNames({\n securityOrigin: request.origin\n })\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n databases: result.databaseNames\n })\n }\n\n assertIndexedDbTarget(request)\n\n if (request.action === 'get') {\n const result = await client.IndexedDB.requestData({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n indexName: request.indexName ?? '',\n skipCount: 0,\n pageSize: 100\n })\n\n return createCdpStorageSuccess(request, {\n entries: result.objectStoreDataEntries,\n hasMore: result.hasMore\n })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n await client.IndexedDB.deleteObjectStoreEntries({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n keyRange: createExactCdpKeyRange(request.key) as never\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'clear') {\n if (request.objectStoreName) {\n await client.IndexedDB.clearObjectStore({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n await client.IndexedDB.deleteDatabase({\n securityOrigin: request.origin,\n databaseName: request.databaseName\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n return createCdpStorageError(\n request,\n 'IndexedDB set operation requires runtime bridge'\n )\n}\n\nfunction isCookieInOrigin(\n cookie: { readonly domain?: string },\n origin: string\n): boolean {\n const hostname = new URL(origin).hostname\n const domain = cookie.domain?.replace(/^\\./, '')\n\n return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)))\n}\n\nfunction normalizeCookieSameSite(\n sameSite?: 'strict' | 'lax' | 'none'\n): 'Strict' | 'Lax' | 'None' | undefined {\n if (!sameSite) {\n return undefined\n }\n\n if (sameSite === 'strict') {\n return 'Strict'\n }\n\n if (sameSite === 'lax') {\n return 'Lax'\n }\n\n return 'None'\n}\n\nfunction createExactCdpKeyRange(key: string): {\n readonly lower: unknown\n readonly upper: unknown\n readonly lowerOpen: boolean\n readonly upperOpen: boolean\n} {\n const parsedKey = parseJsonValue(key)\n\n return {\n lower: parsedKey,\n upper: parsedKey,\n lowerOpen: false,\n upperOpen: false\n }\n}\n\nfunction parseJsonValue(value: string): unknown {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n}\n\nfunction assertStorageKey(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & { readonly key: string } {\n if (!request.key) {\n throw new Error('Storage key is required for this operation')\n }\n}\n\nfunction assertIndexedDbTarget(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n} {\n if (!request.databaseName || !request.objectStoreName) {\n throw new Error('IndexedDB databaseName and objectStoreName are required')\n }\n}\n\nfunction createCdpStorageSuccess(\n request: RuntimeStorageRequest,\n data: unknown\n): RuntimeStorageResult {\n return {\n ok: true,\n source: 'cdp',\n action: request.action,\n scope: request.scope,\n data\n }\n}\n\nfunction createCdpStorageError(\n request: RuntimeStorageRequest,\n error: string\n): RuntimeStorageResult {\n return {\n ok: false,\n source: 'cdp',\n action: request.action,\n scope: request.scope,\n error\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 getElementContext: () => undefined,\n onElementContextUpdated: (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 manageStorage: () => undefined,\n onStorageUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n recordPerformance: () => undefined,\n onPerformanceRecorded: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n startPerformanceRecording: () => undefined,\n onPerformanceRecordingStarted: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n stopPerformanceRecording: () => undefined,\n onPerformanceRecordingStopped: (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","/**\n * Vue SFC 元素标识注入。\n *\n * 该模块只在 Vite dev transform 阶段处理项目源码,把稳定、可读的\n * `data-v-mcp-id` 写到模板元素上;runtime 和 MCP 依赖这个 ID 建立\n * “用户点击 DOM -> AI 定位源码”的协作链路。\n */\n\nimport { parse } from '@vue/compiler-sfc'\nimport MagicString from 'magic-string'\nimport { relative } from 'node:path'\nimport type { TransformResult } from 'vite'\n\nconst VUE_FILE_SUFFIX = '.vue'\nconst ELEMENT_NODE_TYPE = 1\nconst SKIPPED_TAGS = new Set(['template', 'slot', 'script', 'style'])\nconst MCP_ID_ATTR = 'data-v-mcp-id'\n\n/**\n * 元素注入控制器。\n *\n * 返回 `undefined` 表示当前模块不适合注入,Vite 可继续走后续插件。\n */\nexport interface ElementInstrumentationController {\n transform(\n code: string,\n id: string,\n ssr?: boolean\n ): TransformResult | undefined\n}\n\n/**\n * 元素注入控制器配置。\n *\n * root 用于生成项目相对路径,避免把用户机器绝对路径暴露给 AI。\n */\nexport interface ElementInstrumentationOptions {\n readonly root: string\n}\n\ninterface TemplateAstNode {\n readonly type: number\n readonly tag?: string\n readonly loc?: {\n readonly start: {\n readonly line: number\n readonly column: number\n readonly offset: number\n }\n }\n readonly props?: readonly unknown[]\n readonly children?: readonly TemplateAstNode[]\n}\n\n/**\n * 创建元素标识注入控制器。\n *\n * 该控制器只处理本地开发态的项目源码,第三方依赖和虚拟模块必须跳过,\n * 避免把调试属性写入外部包产物或 Vite 内部虚拟模块。\n */\nexport function createElementInstrumentationController(\n options: ElementInstrumentationOptions\n): ElementInstrumentationController {\n return {\n transform(code, id, ssr) {\n if (ssr || shouldSkipInstrumentation(id)) {\n return undefined\n }\n\n const filename = id.split('?', 1)[0]\n\n if (!filename.endsWith(VUE_FILE_SUFFIX)) {\n return undefined\n }\n\n const parsed = parse(code, { filename })\n const template = parsed.descriptor.template\n\n if (!template?.ast) {\n return undefined\n }\n\n const s = new MagicString(code)\n const relativeFile = normalizePath(relative(options.root, filename))\n\n for (const node of template.ast.children) {\n injectNodeId(s, node as TemplateAstNode, relativeFile)\n }\n\n if (!s.hasChanged()) {\n return undefined\n }\n\n return {\n code: s.toString(),\n map: s.generateMap({ hires: true }) as TransformResult extends {\n map?: infer T\n }\n ? T\n : never\n }\n }\n }\n}\n\n/**\n * 判断当前 Vite 模块是否需要跳过注入。\n *\n * 过滤虚拟模块和 `node_modules` 是为了把源码定位限定在用户项目内;\n * SSR transform 由调用方传入,避免服务端渲染路径携带浏览器调试属性。\n */\nfunction shouldSkipInstrumentation(id: string): boolean {\n if (id.startsWith('\\0')) {\n return true\n }\n\n const normalized = normalizePath(id)\n\n if (normalized.includes('/node_modules/')) {\n return true\n }\n\n return !normalized.startsWith('/') && !/^[A-Za-z]:\\//.test(normalized)\n}\n\n/**\n * 统一路径分隔符。\n *\n * elementId 会被用户复制给 AI,跨平台场景下必须固定为 `/` 才便于解析。\n */\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\n/**\n * 递归给模板元素注入源码 ID。\n *\n * Vue 编译器的位置信息已经是源码中的行列号,因此这里不重新计算 offset;\n * 对已有 `data-v-mcp-id` 的元素保持尊重,方便项目手动覆盖或测试固定 ID。\n */\nfunction injectNodeId(\n s: MagicString,\n node: TemplateAstNode,\n relativeFile: string\n): void {\n if (node.type !== ELEMENT_NODE_TYPE || !node.tag || !node.loc) {\n return\n }\n\n if (!SKIPPED_TAGS.has(node.tag) && !hasMcpIdAttr(node)) {\n const id = `${relativeFile}:${String(node.loc.start.line)}:${String(node.loc.start.column)}`\n const insertAt = node.loc.start.offset + node.tag.length + 1\n s.appendLeft(insertAt, ` ${MCP_ID_ATTR}=\"${id}\"`)\n }\n\n for (const child of node.children ?? []) {\n injectNodeId(s, child, relativeFile)\n }\n}\n\n/**\n * 判断模板元素是否已经声明 MCP ID。\n *\n * 通过编译器 props 判断比字符串扫描更稳,避免被文本内容里的同名字符串误判。\n */\nfunction hasMcpIdAttr(node: TemplateAstNode): boolean {\n return (node.props ?? []).some((prop) => {\n if (!isTemplateProp(prop)) {\n return false\n }\n\n return prop.name === MCP_ID_ATTR\n })\n}\n\n/**\n * 收窄 Vue 编译器 prop 节点。\n *\n * 这里故意只读取 `name`,不依赖完整内部类型,减少后续 Vue 编译器小版本变更的影响面。\n */\nfunction isTemplateProp(value: unknown): value is { readonly name?: string } {\n return Boolean(value && typeof value === 'object' && 'name' in value)\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(options, getConfig()?.root)\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(\n options: ResolvedVueMcpNextOptions,\n root?: string\n): 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(${JSON.stringify({\n elementPicker: options.elementPicker,\n projectRoot: root\n })});`\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":["resolve","z","z","snapshot","nodes","z","z","z","z","z","z","z","nanoid","path","resolve","z","z","relative","z","resolve","z","result","cookies","z","result","hasCdpConfig","z","mkdir","writeFile","path","z","isPlainRecord","nanoid","z","z","path","nanoid","resolve","nanoid","nanoid","nanoid","nanoid","relative","normalizePath","path","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","isPerformanceReport"]}
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/elementContext.ts","../src/shared/elementId.ts","../src/mcp/tools/evaluate.ts","../src/cdp/cdpEvaluate.ts","../src/mcp/tools/network.ts","../src/mcp/tools/performance.ts","../src/performance/summary.ts","../src/performance/output.ts","../src/cdp/cdpPerformance.ts","../src/mcp/tools/pages.ts","../src/plugin/entryDiscovery.ts","../src/mcp/tools/storage.ts","../src/cdp/cdpStorage.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/elementInstrumentation.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 {\n DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS,\n DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS,\n mergeOptions,\n RUNTIME_PAGE_CONNECTED_EVENT,\n RUNTIME_PAGE_DISCONNECTED_EVENT,\n RUNTIME_PAGE_HEARTBEAT_EVENT,\n RUNTIME_PAGE_RECONNECTED_EVENT\n} from '../constants'\nimport { createVueMcpNextContext } from '../context'\nimport { createMcpServer } from '../mcp/createMcpServer'\nimport { setupMcpTransport } from '../mcp/transport'\nimport { appendPerformanceReport } from '../mcp/tools/performance'\nimport { createServerVueRuntimeRpc } from '../mcp/vueRpc'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PerformanceReport,\n VueMcpNextOptions\n} from '../types'\nimport { createCdpLifecycleController } from './cdpLifecycle'\nimport { createElementInstrumentationController } from './elementInstrumentation'\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 let elementInstrumentation:\n | ReturnType<typeof createElementInstrumentationController>\n | undefined\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 elementInstrumentation = createElementInstrumentationController({\n root: resolvedConfig.root\n })\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 const lastSeenAt = new Map<string, number>()\n const heartbeatTimer = setInterval(() => {\n const now = Date.now()\n\n for (const [pageId, seenAt] of lastSeenAt) {\n const target = ctx.pages.get(pageId)\n\n if (!target || target.source !== 'runtime' || !target.connected) {\n lastSeenAt.delete(pageId)\n continue\n }\n\n if (now - seenAt >= DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS) {\n ctx.pages.disconnect(pageId, now)\n lastSeenAt.delete(pageId)\n }\n }\n }, DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS)\n\n server.ws.on(RUNTIME_PAGE_CONNECTED_EVENT, (payload: unknown) => {\n if (isRuntimePageTarget(payload)) {\n ctx.pages.upsert(payload)\n lastSeenAt.set(payload.pageId, Date.now())\n void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload)\n void cdpLifecycle.connectPage(payload)\n }\n })\n server.ws.on(RUNTIME_PAGE_HEARTBEAT_EVENT, (payload: unknown) => {\n if (isRuntimeHeartbeatTarget(payload)) {\n const target = ctx.pages.get(payload.pageId)\n\n if (target?.source === 'runtime' && target.connected) {\n lastSeenAt.set(payload.pageId, payload.timestamp)\n }\n }\n })\n server.ws.on(RUNTIME_PAGE_DISCONNECTED_EVENT, (payload: unknown) => {\n if (isRuntimeDisconnectTarget(payload)) {\n ctx.pages.disconnect(payload.pageId)\n lastSeenAt.delete(payload.pageId)\n }\n })\n server.ws.on('vite-plugin-vue-mcp-next:console-record', (payload: unknown) => {\n if (isConsoleRecord(payload)) {\n ctx.consoleRecords.push(payload)\n }\n })\n server.ws.on('vite-plugin-vue-mcp-next:network-record', (payload: unknown) => {\n if (isNetworkRecord(payload)) {\n ctx.networkRecords.push(payload)\n }\n })\n server.ws.on(\n 'vite-plugin-vue-mcp-next:performance-record',\n (payload: unknown) => {\n if (isPerformanceReport(payload)) {\n appendPerformanceReport(ctx, 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 clearInterval(heartbeatTimer)\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 const instrumented = elementInstrumentation?.transform(\n code,\n id,\n transformOptions?.ssr\n )\n const nextCode =\n instrumented &&\n typeof instrumented === 'object' &&\n 'code' in instrumented &&\n typeof instrumented.code === 'string'\n ? instrumented.code\n : code\n const runtimeInjected = runtimeInjection.transform(\n nextCode,\n id,\n transformOptions?.ssr\n )\n\n if (runtimeInjected) {\n return runtimeInjected\n }\n\n return instrumented\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 (target.runtimeClientId === undefined ||\n typeof target.runtimeClientId === 'string')\n )\n}\n\n/**\n * 校验 runtime 心跳载荷。\n *\n * 心跳只负责刷新活性时间,不应允许服务端接受结构不完整的数据。\n */\nfunction isRuntimeHeartbeatTarget(\n payload: unknown\n): payload is { readonly pageId: string; readonly timestamp: number } {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<{ pageId: string; timestamp: number }>\n\n return typeof target.pageId === 'string' && typeof target.timestamp === 'number'\n}\n\n/**\n * 校验 runtime 主动断开载荷。\n *\n * 断开事件只需要 pageId,避免把页面卸载过程里的其他状态误当成服务端输入。\n */\nfunction isRuntimeDisconnectTarget(\n payload: unknown\n): payload is { readonly pageId: string } {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const target = payload as Partial<{ pageId: string }>\n\n return typeof target.pageId === 'string'\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 * 校验 performance hook 上报记录。\n *\n * 性能报告由浏览器运行时主动推送,服务端只接收足以完成缓存和查询的最小字段,\n * 避免异常 payload 污染 `get_performance_report` 的结果。\n */\nfunction isPerformanceReport(payload: unknown): payload is PerformanceReport {\n if (!payload || typeof payload !== 'object') {\n return false\n }\n\n const report = payload as Partial<PerformanceReport>\n\n return (\n typeof report.recordingId === 'string' &&\n typeof report.pageId === 'string' &&\n (report.source === 'hook' || report.source === 'cdp') &&\n Boolean(report.summary) &&\n Array.isArray(report.longTasks) &&\n Array.isArray(report.limitations)\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/** 默认性能诊断保存目录,原始 profile 和 heap 文件都应保存在项目内。 */\nexport const DEFAULT_PERFORMANCE_SAVE_DIR = '.vite-mcp/performance'\n\n/** 默认性能报告缓冲上限,避免长时间会话无限累积历史诊断结果。 */\nexport const DEFAULT_PERFORMANCE_MAX_REPORTS = 100\n\n/** 默认性能诊断最大时长,避免一次采集长时间占用浏览器资源。 */\nexport const DEFAULT_PERFORMANCE_MAX_DURATION_MS = 30_000\n\n/** 默认性能诊断采样间隔,兼顾趋势判断和额外采样开销。 */\nexport const DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS = 250\n\n/** 默认长任务阈值,沿用浏览器 Long Task 的常见卡顿判断口径。 */\nexport const DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS = 50\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 listStorage: 'list_storage',\n getStorageItem: 'get_storage_item',\n setStorageItem: 'set_storage_item',\n deleteStorageItem: 'delete_storage_item',\n clearStorage: 'clear_storage',\n recordPerformance: 'record_performance',\n startPerformanceRecording: 'start_performance_recording',\n stopPerformanceRecording: 'stop_performance_recording',\n getPerformanceReport: 'get_performance_report',\n takeHeapSnapshot: 'take_heap_snapshot',\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 getElementContext: 'get_element_context'\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/** Runtime 页面连接事件名,供 runtime client 启动时上报页面进入。 */\nexport const RUNTIME_PAGE_CONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-connected'\n\n/** Runtime 页面断开事件名,供页面卸载时主动通知服务端清理目标。 */\nexport const RUNTIME_PAGE_DISCONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-disconnected'\n\n/** Runtime 页面心跳事件名,供服务端兜底判断页面是否失活。 */\nexport const RUNTIME_PAGE_HEARTBEAT_EVENT =\n 'vite-plugin-vue-mcp-next:heartbeat'\n\n/** Runtime 页面心跳间隔,保持较低流量并覆盖正常关闭场景。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_INTERVAL_MS = 15_000\n\n/** Runtime 页面失活阈值,留出心跳抖动和短暂阻塞的缓冲。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45_000\n\n/** Runtime 页面兜底扫描间隔,和失活阈值保持一致以减少无意义轮询。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45_000\n\n/** 元素选择器轻提示默认时长,足够用户看清复制结果且不长期遮挡页面。 */\nexport const DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS = 2_200\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 elementPicker: {\n enabled: true,\n shortcut: {\n altKey: true,\n shiftKey: true,\n metaKey: false,\n ctrlKey: false\n },\n toastDurationMs: DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS\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 performance: {\n mode: 'auto',\n maxDurationMs: DEFAULT_PERFORMANCE_MAX_DURATION_MS,\n sampleIntervalMs: DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS,\n longTaskThresholdMs: DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS,\n saveDir: DEFAULT_PERFORMANCE_SAVE_DIR,\n memory: {\n enabled: true\n },\n stacks: {\n enabled: true\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 elementPicker: {\n ...DEFAULT_OPTIONS.elementPicker,\n ...options.elementPicker,\n shortcut: {\n ...DEFAULT_OPTIONS.elementPicker.shortcut,\n ...options.elementPicker?.shortcut\n }\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 performance: {\n ...DEFAULT_OPTIONS.performance,\n ...options.performance,\n memory: {\n ...DEFAULT_OPTIONS.performance.memory,\n ...options.performance?.memory\n },\n stacks: {\n ...DEFAULT_OPTIONS.performance.stacks,\n ...options.performance?.stacks\n }\n }\n }\n}\n","/**\n * 插件运行时共享上下文。\n *\n * 该文件集中维护 MCP 工具、Runtime Bridge 与 CDP Adapter 共用的状态容器,\n * 避免页面、日志和网络缓存分散在各工具模块后出现生命周期不一致。\n */\nimport { createHooks } from 'hookable'\nimport { createRingBuffer } from './shared/ringBuffer'\nimport { DEFAULT_PERFORMANCE_MAX_REPORTS } from './constants'\nimport type {\n ConsoleRecord,\n NetworkRecord,\n PageTarget,\n PageTargetListOptions,\n PageTargetRegistry,\n ResolvedVueMcpNextOptions,\n PerformanceReport,\n PerformanceSession,\n VueMcpNextContext\n} from './types'\n\n/** 一分钟毫秒数,用于声明 runtime 断开记录保留窗口。 */\nconst MINUTE_MS = 60 * 1000\n/** 断开的 runtime 页面只短期保留,避免长期开发会话不断累积历史目标。 */\nconst DISCONNECTED_RUNTIME_TARGET_RETENTION_MS = 5 * MINUTE_MS\n\n/**\n * 判断断开的 runtime 目标是否已经超过保留窗口。\n *\n * 只清理 runtime 历史记录,避免 CDP target 因浏览器临时状态被插件侧误删。\n */\nfunction shouldPruneDisconnectedRuntimeTarget(\n target: PageTarget,\n now: number\n): boolean {\n return (\n target.source === 'runtime' &&\n !target.connected &&\n typeof target.disconnectedAt === 'number' &&\n now - target.disconnectedAt > DISCONNECTED_RUNTIME_TARGET_RETENTION_MS\n )\n}\n\n/**\n * 清理过期的断开 runtime 目标。\n *\n * registry 的公开操作都会调用该函数,让页面列表长期使用时不会无限保留刷新历史。\n */\nfunction pruneDisconnectedRuntimeTargets(\n targets: Map<string, PageTarget>,\n now: number\n): void {\n for (const [pageId, target] of targets) {\n if (shouldPruneDisconnectedRuntimeTarget(target, now)) {\n targets.delete(pageId)\n }\n }\n}\n\n/**\n * 标记页面目标断开。\n *\n * 断开时间只在从 connected 变为 disconnected 时写入,避免重复 disconnect 延长过期记录寿命。\n */\nfunction markTargetDisconnected(target: PageTarget, now: number): PageTarget {\n return {\n ...target,\n connected: false,\n disconnectedAt: target.disconnectedAt ?? now\n }\n}\n\n/**\n * 判断页面目标是否应出现在日常页面列表中。\n *\n * 默认只隐藏断开的 runtime 历史记录;CDP target 是否可连由 CDP 返回值表达,不在这里裁剪。\n */\nfunction shouldListPageTarget(\n target: PageTarget,\n options: PageTargetListOptions\n): boolean {\n return (\n options.includeDisconnected === true ||\n target.source !== 'runtime' ||\n target.connected\n )\n}\n\n/**\n * 断开同一浏览器标签页的旧 runtime 目标。\n *\n * runtime 刷新或 HMR 重连会产生新的 pageId,但同一个 sessionStorage client id 代表同一标签页;\n * 保留旧记录为 disconnected 可以解释历史目标,同时避免 `list_pages` 出现多个可操作的重复页面。\n */\nfunction disconnectPreviousRuntimeClientTarget(\n targets: Map<string, PageTarget>,\n target: PageTarget,\n now: number\n): void {\n if (target.source !== 'runtime' || !target.runtimeClientId) {\n return\n }\n\n for (const [pageId, currentTarget] of targets) {\n if (\n pageId === target.pageId ||\n currentTarget.source !== 'runtime' ||\n currentTarget.runtimeClientId !== target.runtimeClientId ||\n !currentTarget.connected\n ) {\n continue\n }\n\n targets.set(pageId, markTargetDisconnected(currentTarget, now))\n }\n}\n\n/**\n * 创建页面目标注册表。\n *\n * 独立工厂便于单元测试,也避免上下文对象承担过多数据结构细节。\n */\nexport function createPageTargetRegistry(): PageTargetRegistry {\n const targets = new Map<string, PageTarget>()\n\n return {\n upsert(target, now = Date.now()) {\n pruneDisconnectedRuntimeTargets(targets, now)\n disconnectPreviousRuntimeClientTarget(targets, target, now)\n targets.set(target.pageId, target)\n },\n get(pageId) {\n return targets.get(pageId)\n },\n list(options = {}) {\n const now = options.now ?? Date.now()\n pruneDisconnectedRuntimeTargets(targets, now)\n\n return [...targets.values()].filter((target) =>\n shouldListPageTarget(target, options)\n )\n },\n disconnect(pageId, now = Date.now()) {\n pruneDisconnectedRuntimeTargets(targets, now)\n const target = targets.get(pageId)\n\n if (!target) {\n return\n }\n\n targets.set(pageId, markTargetDisconnected(target, now))\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 performanceReports: createRingBuffer<PerformanceReport>(\n DEFAULT_PERFORMANCE_MAX_REPORTS\n ),\n performanceSessions: new Map<string, PerformanceSession>()\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 { registerElementContextTools } from './tools/elementContext'\nimport { registerEvaluateTools } from './tools/evaluate'\nimport { registerNetworkTools } from './tools/network'\nimport { registerPerformanceTools } from './tools/performance'\nimport { registerPageTools } from './tools/pages'\nimport { registerStorageTools } from './tools/storage'\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 registerElementContextTools(server, ctx)\n registerScreenshotTools(server, ctx)\n registerConsoleTools(server, ctx)\n registerEvaluateTools(server, ctx)\n registerNetworkTools(server, ctx)\n registerStorageTools(server, ctx)\n registerPerformanceTools(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","/**\n * MCP 元素上下文工具。\n *\n * 工具只接受用户已经复制的 elementId,不阻塞等待浏览器点击;\n * runtime 在线时返回组件和 DOM 增强信息,离线时仍能解析项目源码或第三方包边界。\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport { parseElementId } from '../../shared/elementId'\nimport type { ElementContextResult, VueMcpNextContext } from '../../types'\nimport {\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} from '../routeTools'\n\n/**\n * 注册元素上下文查询工具。\n *\n * 该工具只按用户提供的 elementId 查询上下文,不等待浏览器点击,避免 MCP 请求长期悬挂。\n */\nexport function registerElementContextTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.getElementContext,\n {\n description:\n 'Get editable source, Vue component, and DOM context for a copied elementId.',\n inputSchema: {\n elementId: z.string(),\n pageId: z.string().optional()\n }\n },\n async (input) => {\n const runtimeResult = await tryRuntimeElementContext(\n ctx,\n input.elementId,\n input.pageId\n )\n\n if (runtimeResult) {\n return createToolResponse(runtimeResult)\n }\n\n return createToolResponse(createStaticElementContext(input.elementId))\n }\n )\n}\n\n/**\n * 尝试通过浏览器 runtime 获取完整元素上下文。\n *\n * 项目源码和第三方包 ID 可以静态解析;runtime ID 必须依赖浏览器页面,否则无法反查 DOM 引用。\n */\nasync function tryRuntimeElementContext(\n ctx: VueMcpNextContext,\n elementId: string,\n pageId?: string\n): Promise<ElementContextResult | undefined> {\n if (!ctx.rpcServer) {\n return parseElementId(elementId).kind === 'runtime'\n ? createRuntimeUnavailableContext(elementId)\n : undefined\n }\n\n try {\n resolvePageTarget(ctx, pageId)\n } catch (error) {\n const parsed = parseElementId(elementId)\n\n if (parsed.kind === 'project-source' || parsed.kind === 'package') {\n return undefined\n }\n\n return {\n ok: false,\n elementId,\n error: error instanceof Error ? error.message : String(error),\n limitations: ['call list_pages and pass pageId when multiple pages exist']\n }\n }\n\n return (await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.getElementContext({ event, elementId })\n })) as ElementContextResult\n}\n\n/**\n * 创建静态元素上下文。\n *\n * 静态 fallback 不依赖浏览器页面,因此只能返回源码位置或第三方包边界,不能提供 DOM/组件摘要。\n */\nfunction createStaticElementContext(elementId: string): ElementContextResult {\n const parsed = parseElementId(elementId)\n\n if (parsed.kind === 'project-source') {\n return {\n ok: true,\n elementId,\n editable: true,\n codeLocation: {\n file: parsed.file,\n line: parsed.line,\n column: parsed.column\n },\n limitations: ['runtime unavailable, DOM and component context omitted']\n }\n }\n\n if (parsed.kind === 'package') {\n return {\n ok: true,\n elementId,\n editable: false,\n packageLocation: {\n packageName: parsed.packageName,\n entryFile: parsed.entryFile\n },\n limitations: ['third-party package source is not editable from this project']\n }\n }\n\n if (parsed.kind === 'runtime') {\n return createRuntimeUnavailableContext(elementId)\n }\n\n return {\n ok: false,\n elementId,\n error: parsed.reason,\n limitations: ['please provide a copied elementId from the element picker']\n }\n}\n\n/**\n * 创建 runtime 不可用错误。\n *\n * runtime ID 没有静态含义,浏览器断开后必须要求用户重新选择。\n */\nfunction createRuntimeUnavailableContext(elementId: string): ElementContextResult {\n return {\n ok: false,\n elementId,\n error: 'runtime bridge is not connected',\n limitations: ['runtime ids are only valid while the page is connected']\n }\n}\n","/**\n * 元素 ID 共享解析契约。\n *\n * 该文件只处理字符串格式分类,不访问 DOM、runtime 或文件系统;\n * 这样 MCP 在浏览器页面不在线时,仍能基于用户提供的 ID 返回明确边界。\n */\n\nconst PROJECT_SOURCE_ID_PATTERN = /^(.+\\.(?:vue|tsx|jsx|ts|js)):(\\d+):(\\d+)$/\nconst RUNTIME_ID_PATTERN = /^runtime:([A-Za-z0-9_-]+)$/\nconst PACKAGE_ID_PREFIX = 'pkg:'\n\n/**\n * 元素 ID 解析结果。\n *\n * `project-source` 表示可定位到项目源码;`package` 只表达第三方包入口;\n * `runtime` 依赖当前页面生命周期;`invalid` 用于给 AI 返回可解释错误。\n */\nexport type ParsedElementId =\n | {\n readonly kind: 'project-source'\n readonly elementId: string\n readonly file: string\n readonly line: number\n readonly column: number\n }\n | {\n readonly kind: 'package'\n readonly elementId: string\n readonly packageName: string\n readonly entryFile: string\n }\n | {\n readonly kind: 'runtime'\n readonly elementId: string\n readonly runtimeId: string\n }\n | {\n readonly kind: 'invalid'\n readonly elementId: string\n readonly reason: string\n }\n\n/**\n * 解析用户复制给 AI 的元素标识。\n *\n * 该函数只负责格式分类,不判断文件是否存在,也不推断 DOM 是否仍在页面上;\n * 这些上下文需要由 runtime 或 MCP 上层工具补齐。\n */\nexport function parseElementId(elementId: string): ParsedElementId {\n const sourceMatch = PROJECT_SOURCE_ID_PATTERN.exec(elementId)\n\n if (sourceMatch) {\n return {\n kind: 'project-source',\n elementId,\n file: sourceMatch[1],\n line: Number(sourceMatch[2]),\n column: Number(sourceMatch[3])\n }\n }\n\n if (elementId.startsWith(PACKAGE_ID_PREFIX)) {\n return parsePackageElementId(elementId)\n }\n\n const runtimeMatch = RUNTIME_ID_PATTERN.exec(elementId)\n\n if (runtimeMatch) {\n return {\n kind: 'runtime',\n elementId,\n runtimeId: runtimeMatch[1]\n }\n }\n\n return {\n kind: 'invalid',\n elementId,\n reason: 'unsupported elementId format'\n }\n}\n\n/**\n * 解析第三方包元素标识。\n *\n * scope 包需要把前两段作为包名,避免把 `@scope/ui/Button` 错切成 `@scope`;\n * 包级 ID 不返回 `node_modules` 物理路径,避免引导 AI 修改依赖源码。\n */\nfunction parsePackageElementId(elementId: string): ParsedElementId {\n const value = elementId.slice(PACKAGE_ID_PREFIX.length)\n const parts = value.split('/').filter(Boolean)\n\n if (parts.length < 2) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include packageName and entryFile'\n }\n }\n\n const scoped = parts[0]?.startsWith('@')\n const packageName = scoped ? parts.slice(0, 2).join('/') : parts[0]\n const entryFile = parts.slice(scoped ? 2 : 1).join('/')\n\n if (!entryFile) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include entryFile'\n }\n }\n\n return {\n kind: 'package',\n elementId,\n packageName,\n entryFile\n }\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","/**\n * MCP 性能诊断工具。\n *\n * 该文件把 runtime 轻量采样和 CDP 深度采样统一成一组工具,适合分析页面是否卡顿、\n * 是否存在内存增长,以及在调试权限可用时进一步拿到 CPU profile 和 heap snapshot。\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type CDP from 'chrome-remote-interface'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport { z } from 'zod'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport {\n recordCdpPerformance,\n startCdpPerformanceRecording,\n stopCdpPerformanceRecording,\n takeHeapSnapshot\n} from '../../cdp/cdpPerformance'\nimport type {\n PerformanceReport,\n VueMcpNextContext\n} from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData\n} from '../routeTools'\n\nconst PERFORMANCE_NOT_AVAILABLE_ERROR =\n 'Performance diagnostics are disabled by configuration'\n\nconst activeCdpPerformanceClients = new Map<string, CDP.Client>()\n\ntype PerformanceCdpConnection = NonNullable<\n Awaited<ReturnType<typeof connectCdpForPage>>\n>\n\ninterface PerformanceCdpConnectResult {\n /** CDP 连接成功时返回可直接用于性能采样的客户端。 */\n readonly cdp?: PerformanceCdpConnection\n /** CDP 端口不可达或 target 查询失败时保留原始错误,强制 CDP 模式需要向用户说明原因。 */\n readonly error?: string\n}\n\n/**\n * 注册性能诊断工具。\n *\n * 这组工具同时覆盖无调试权限的 runtime 采样和有 CDP 权限的深度诊断,\n * 让上层只需要关心“是否卡顿”和“能否进一步看 profile”两个层次。\n */\nexport function registerPerformanceTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n server.registerTool(\n MCP_TOOL_NAMES.recordPerformance,\n {\n description: 'Record a performance sample for the selected page.',\n inputSchema: {\n pageId: z.string().optional(),\n durationMs: z.number().optional(),\n includeMemory: z.boolean().optional(),\n includeStacks: z.boolean().optional()\n }\n },\n async (input) => handleRecordPerformance(ctx, input as RecordPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.startPerformanceRecording,\n {\n description: 'Start a performance recording session.',\n inputSchema: {\n pageId: z.string().optional(),\n includeMemory: z.boolean().optional(),\n includeStacks: z.boolean().optional()\n }\n },\n async (input) =>\n handleStartPerformanceRecording(ctx, input as StartPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.stopPerformanceRecording,\n {\n description: 'Stop a performance recording session.',\n inputSchema: {\n recordingId: z.string()\n }\n },\n async (input) =>\n handleStopPerformanceRecording(ctx, input as StopPerformanceInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.getPerformanceReport,\n {\n description: 'Get cached performance reports and active sessions.',\n inputSchema: {\n pageId: z.string().optional(),\n recordingId: z.string().optional(),\n limit: z.number().optional()\n }\n },\n (input) => handleGetPerformanceReport(ctx, input as GetReportInput)\n )\n\n server.registerTool(\n MCP_TOOL_NAMES.takeHeapSnapshot,\n {\n description: 'Take a heap snapshot with CDP.',\n inputSchema: {\n pageId: z.string().optional()\n }\n },\n async (input) =>\n handleTakeHeapSnapshot(ctx, input as TakeHeapSnapshotInput)\n )\n}\n\n/**\n * 追加性能报告到缓存。\n *\n * runtime 热推送和 tool 返回可能会同时命中同一份报告,因此这里只做幂等写入,\n * 避免同一个 recordingId 在缓存里重复占位。\n */\nexport function appendPerformanceReport(\n ctx: VueMcpNextContext,\n report: PerformanceReport\n): void {\n if (\n ctx.performanceReports\n .all()\n .some((item) => item.recordingId === report.recordingId)\n ) {\n return\n }\n\n ctx.performanceReports.push(report)\n}\n\n/**\n * 性能采样输入。\n */\ninterface RecordPerformanceInput {\n readonly pageId?: string\n readonly durationMs?: number\n readonly includeMemory?: boolean\n readonly includeStacks?: boolean\n}\n\n/**\n * 性能录制启动输入。\n */\ninterface StartPerformanceInput {\n readonly pageId?: string\n readonly includeMemory?: boolean\n readonly includeStacks?: boolean\n}\n\n/**\n * 性能录制停止输入。\n */\ninterface StopPerformanceInput {\n readonly recordingId: string\n}\n\n/**\n * 性能报告查询输入。\n */\ninterface GetReportInput {\n readonly pageId?: string\n readonly recordingId?: string\n readonly limit?: number\n}\n\n/**\n * heap snapshot 输入。\n */\ninterface TakeHeapSnapshotInput {\n readonly pageId?: string\n}\n\n/**\n * 执行一次性能采样。\n */\nasync function handleRecordPerformance(\n ctx: VueMcpNextContext,\n input: RecordPerformanceInput\n): Promise<CallToolResult> {\n const durationMs = input.durationMs ?? ctx.options.performance.maxDurationMs\n const includeMemory =\n input.includeMemory ?? ctx.options.performance.memory.enabled\n const includeStacks =\n input.includeStacks ?? ctx.options.performance.stacks.enabled\n\n if (ctx.options.performance.mode === 'off') {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n if (ctx.options.performance.mode !== 'hook') {\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (cdp) {\n try {\n const report = await recordCdpPerformance({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n durationMs,\n includeMemory,\n includeStacks,\n saveDir: ctx.options.performance.saveDir\n })\n appendPerformanceReport(ctx, report)\n\n return createToolResponse(toStructuredRecord(report))\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n if (ctx.options.performance.mode === 'cdp') {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP performance collection is unavailable',\n cdpResult.error\n )\n )\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.recordPerformance({\n event,\n durationMs,\n includeMemory,\n includeStacks\n })\n })\n\n if (isPerformanceReport(result)) {\n appendPerformanceReport(ctx, result)\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n}\n\n/**\n * 开始一次性能录制。\n */\nasync function handleStartPerformanceRecording(\n ctx: VueMcpNextContext,\n input: StartPerformanceInput\n): Promise<CallToolResult> {\n const includeMemory =\n input.includeMemory ?? ctx.options.performance.memory.enabled\n const includeStacks =\n input.includeStacks ?? ctx.options.performance.stacks.enabled\n\n if (ctx.options.performance.mode === 'off') {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n if (ctx.options.performance.mode !== 'hook') {\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (cdp) {\n try {\n const session = await startCdpPerformanceRecording({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n includeMemory,\n includeStacks,\n saveDir: ctx.options.performance.saveDir\n })\n\n ctx.performanceSessions.set(session.recordingId, {\n recordingId: session.recordingId,\n pageId: session.pageId,\n source: 'cdp',\n startedAt: session.startedAt,\n includeMemory,\n includeStacks,\n mode: ctx.options.performance.mode\n })\n activeCdpPerformanceClients.set(session.recordingId, cdp.client)\n\n return createToolResponse(\n toStructuredRecord({\n ...session,\n source: 'cdp'\n })\n )\n } catch (error) {\n await closeCdpClient(cdp.client)\n return createToolError(\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n\n if (ctx.options.performance.mode === 'cdp') {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP performance collection is unavailable',\n cdpResult.error\n )\n )\n }\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.startPerformanceRecording({\n event,\n includeMemory,\n includeStacks\n })\n })\n\n if (isPerformanceStartResult(result)) {\n ctx.performanceSessions.set(result.recordingId, {\n recordingId: result.recordingId,\n pageId: input.pageId ?? 'runtime',\n source: 'hook',\n startedAt: result.startedAt,\n includeMemory,\n includeStacks,\n mode: ctx.options.performance.mode\n })\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n}\n\n/**\n * 结束一次性能录制。\n */\nasync function handleStopPerformanceRecording(\n ctx: VueMcpNextContext,\n input: StopPerformanceInput\n): Promise<CallToolResult> {\n const session = ctx.performanceSessions.get(input.recordingId)\n\n if (!session) {\n return createToolError(`Performance recording not found: ${input.recordingId}`)\n }\n\n try {\n if (session.source === 'cdp') {\n const client = activeCdpPerformanceClients.get(input.recordingId)\n\n if (!client) {\n return createToolError(\n `CDP client not found for recording: ${input.recordingId}`\n )\n }\n\n const report = await stopCdpPerformanceRecording({\n client,\n session\n })\n appendPerformanceReport(ctx, report)\n\n return createToolResponse(toStructuredRecord(report))\n }\n\n const result = await requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.stopPerformanceRecording({\n event,\n recordingId: input.recordingId\n })\n })\n\n if (isPerformanceReport(result)) {\n appendPerformanceReport(ctx, result)\n }\n\n if (isPlainRecord(result)) {\n return createToolResponse(toStructuredRecord(result))\n }\n\n return createToolError('runtime bridge returned an invalid response')\n } finally {\n ctx.performanceSessions.delete(input.recordingId)\n const client = activeCdpPerformanceClients.get(input.recordingId)\n\n if (client) {\n activeCdpPerformanceClients.delete(input.recordingId)\n await closeCdpClient(client)\n }\n }\n}\n\n/**\n * 查询缓存中的性能报告。\n */\nfunction handleGetPerformanceReport(\n ctx: VueMcpNextContext,\n input: GetReportInput\n): CallToolResult {\n const reports = ctx.performanceReports\n .all()\n .filter((report) => !input.pageId || report.pageId === input.pageId)\n .filter(\n (report) => !input.recordingId || report.recordingId === input.recordingId\n )\n const limit = input.limit ?? reports.length\n\n return createToolResponse(toStructuredRecord({\n report: reports.at(-1) ?? null,\n reports: reports.slice(-limit),\n sessions: [...ctx.performanceSessions.values()].filter(\n (session) =>\n (!input.pageId || session.pageId === input.pageId) &&\n (!input.recordingId || session.recordingId === input.recordingId)\n )\n }))\n}\n\n/**\n * 采集 heap snapshot。\n */\nasync function handleTakeHeapSnapshot(\n ctx: VueMcpNextContext,\n input: TakeHeapSnapshotInput\n): Promise<CallToolResult> {\n if (\n ctx.options.performance.mode === 'off' ||\n ctx.options.performance.mode === 'hook'\n ) {\n return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR)\n }\n\n const cdpResult = await connectPerformanceCdp(ctx, input.pageId)\n const cdp = cdpResult.cdp\n\n if (!cdp) {\n return createToolError(\n formatCdpUnavailableError(\n 'CDP heap snapshot is unavailable',\n cdpResult.error\n )\n )\n }\n\n try {\n return createToolResponse(\n toStructuredRecord(await takeHeapSnapshot({\n client: cdp.client,\n pageId: input.pageId ?? 'cdp',\n saveDir: ctx.options.performance.saveDir\n }))\n )\n } finally {\n await closeCdpClient(cdp.client)\n }\n}\n\n/**\n * 尝试建立性能诊断专用 CDP 连接。\n *\n * `auto` 模式的核心承诺是“有调试权限走 CDP,没有调试权限退回 Runtime Hook”,\n * 因此 CDP discovery 的网络失败不能直接打断性能工具;只有强制 CDP 的工具分支才会把错误返回给用户。\n */\nasync function connectPerformanceCdp(\n ctx: VueMcpNextContext,\n pageId?: string\n): Promise<PerformanceCdpConnectResult> {\n try {\n return { cdp: await connectCdpForPage(ctx, pageId) }\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error)\n }\n }\n}\n\n/**\n * 格式化 CDP 不可用错误。\n *\n * 强制 CDP 模式需要暴露底层原因方便用户检查 `--remote-debugging-port`,\n * 但普通不可用场景仍保持稳定的工具错误前缀,避免调用方只靠文案判断时被破坏。\n */\nfunction formatCdpUnavailableError(message: string, reason?: string): string {\n if (!reason) {\n return message\n }\n\n return `${message}: ${reason}`\n}\n\n/**\n * 判断 runtime 回包是否为性能报告。\n */\nfunction isPerformanceReport(value: unknown): value is PerformanceReport {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const report = value as Partial<PerformanceReport>\n\n return (\n typeof report.recordingId === 'string' &&\n typeof report.pageId === 'string' &&\n (report.source === 'hook' || report.source === 'cdp') &&\n typeof report.startedAt === 'number' &&\n typeof report.endedAt === 'number' &&\n typeof report.durationMs === 'number' &&\n Boolean(report.summary) &&\n Array.isArray(report.longTasks) &&\n Array.isArray(report.limitations)\n )\n}\n\n/**\n * 判断 runtime 回包是否为录制启动结果。\n */\nfunction isPerformanceStartResult(\n value: unknown\n): value is { recordingId: string; startedAt: number } {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const result = value as Partial<{ recordingId: string; startedAt: number }>\n\n return (\n typeof result.recordingId === 'string' &&\n typeof result.startedAt === 'number'\n )\n}\n\n/**\n * 判断值是否为可直接返回给 MCP 的普通对象。\n */\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * 将任意对象收敛为 MCP 需要的普通 record。\n */\nfunction toStructuredRecord(value: unknown): Record<string, unknown> {\n if (isPlainRecord(value)) {\n return value\n }\n\n return {}\n}\n","/**\n * 性能报告摘要计算。\n *\n * 这个文件只保留纯数据归纳逻辑,不依赖浏览器 API 或 CDP client,便于 runtime 和 CDP 两条路径共享同一口径。\n */\nimport { DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS } from '../constants'\nimport type {\n LongTaskRecord,\n MemorySample,\n MemorySummary,\n PerformanceSummary,\n StackFrameSummary,\n StackSummary\n} from '../types'\n\n/**\n * 计算性能摘要。\n *\n * 该摘要面向快速判断页面是否明显卡顿,不追求把所有原始信号都塞进结果里。\n */\nexport function buildPerformanceSummary(input: {\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n}): PerformanceSummary {\n const memory = buildMemorySummary(input.memorySamples)\n const blockedTimeMs = input.longTasks.reduce((total, task) => {\n return (\n total +\n Math.max(0, task.durationMs - DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS)\n )\n }, 0)\n const longTaskCount = input.longTasks.length\n const durations = input.longTasks.map((task) => task.durationMs)\n const maxTaskDurationMs = durations.length ? Math.max(...durations) : 0\n const averageTaskDurationMs = durations.length\n ? Math.round(\n durations.reduce((total, duration) => total + duration, 0) /\n durations.length\n )\n : undefined\n const suspectedJank =\n blockedTimeMs > 0 || memory.trend === 'growing' || longTaskCount > 0\n const severity = resolveSeverity({\n blockedTimeMs,\n longTaskCount,\n memoryTrend: memory.trend\n })\n\n return {\n blockedTimeMs,\n longTaskCount,\n maxTaskDurationMs,\n averageTaskDurationMs,\n suspectedJank,\n severity\n }\n}\n\n/**\n * 计算内存趋势。\n *\n * 只比较首尾和峰值,不推断对象引用关系,这样 runtime-only 路径也能给出稳定结论。\n */\nexport function buildMemorySummary(samples: MemorySample[]): MemorySummary {\n const first = samples[0]?.usedJSHeapSize\n const last = samples.at(-1)?.usedJSHeapSize\n const peak = samples.reduce((currentPeak, sample) => {\n if (typeof sample.usedJSHeapSize !== 'number') {\n return currentPeak\n }\n\n return Math.max(currentPeak, sample.usedJSHeapSize)\n }, 0)\n\n const trend = resolveMemoryTrend(first, last)\n\n return {\n samples,\n initialUsedJSHeapSize: first,\n finalUsedJSHeapSize: last,\n peakUsedJSHeapSize: peak || undefined,\n deltaUsedJSHeapSize:\n typeof first === 'number' && typeof last === 'number'\n ? last - first\n : undefined,\n trend\n }\n}\n\n/**\n * 计算堆栈摘要。\n *\n * 该函数只做排序和裁剪,不直接理解 CPU profile 或错误对象,方便 CDP 和 runtime 传入不同来源的帧数据。\n */\nexport function buildStackSummary(\n frames: StackFrameSummary[],\n options: { rawProfilePath?: string; limitation?: string } = {}\n): StackSummary {\n return {\n topFrames: [...frames].sort(sortByHotness).slice(0, 10),\n rawProfilePath: options.rawProfilePath,\n limitation: options.limitation\n }\n}\n\n/**\n * 根据卡顿指标判断严重程度。\n *\n * 这个分级只用于调试报告的阅读提示,不代表生产级告警阈值。\n */\nfunction resolveSeverity(input: {\n blockedTimeMs: number\n longTaskCount: number\n memoryTrend: MemorySummary['trend']\n}): PerformanceSummary['severity'] {\n if (input.blockedTimeMs >= 1000 || input.longTaskCount >= 10) {\n return 'critical'\n }\n\n if (input.blockedTimeMs > 0 || input.memoryTrend === 'growing') {\n return 'warning'\n }\n\n return 'ok'\n}\n\n/**\n * 根据首尾内存采样判断趋势。\n *\n * 只要存在明显上升就视为 growing,避免 runtime 路径因单次抖动而过度乐观。\n */\nfunction resolveMemoryTrend(\n first: number | undefined,\n last: number | undefined\n): MemorySummary['trend'] {\n if (typeof first !== 'number' || typeof last !== 'number') {\n return 'unknown'\n }\n\n if (last > first) {\n return 'growing'\n }\n\n return 'stable'\n}\n\n/**\n * 按热点程度给堆栈帧排序。\n *\n * 优先比较总耗时,再比较自身耗时和命中次数,保证摘要更偏向真正的热点函数。\n */\nfunction sortByHotness(\n left: StackFrameSummary,\n right: StackFrameSummary\n): number {\n return compareNumber(right.totalTimeMs, left.totalTimeMs)\n || compareNumber(right.selfTimeMs, left.selfTimeMs)\n || compareNumber(right.hitCount, left.hitCount)\n}\n\n/**\n * 比较可选数值。\n *\n * 空值统一排后,方便摘要维持稳定排序。\n */\nfunction compareNumber(left?: number, right?: number): number {\n return (left ?? -1) - (right ?? -1)\n}\n","/**\n * 性能产物落盘 helper。\n *\n * CDP 侧原始 profile 和 heap snapshot 都可能很大,因此需要统一把它们写进项目目录并返回路径型结果。\n */\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { relative, resolve } from 'node:path'\nimport { nanoid } from 'nanoid'\nimport type { PerformanceArtifact } from '../types'\n\n/**\n * 落盘性能产物的输入。\n *\n * helper 只处理文件路径、字节大小和写入,不关心调用方是 CPU profile 还是 heap snapshot。\n */\nexport interface WritePerformanceArtifactOptions {\n /** 项目根目录。 */\n readonly root?: string\n /** 保存目录,相对路径按项目根目录解析。 */\n readonly saveDir: string\n /** 文件名,调用方负责决定扩展名和语义前缀。 */\n readonly fileName: string\n /** 产物类型。 */\n readonly kind: PerformanceArtifact['kind']\n /** 原始数据。 */\n readonly data: string | Buffer\n}\n\n/**\n * 把性能产物写入磁盘。\n *\n * 这个 helper 会创建保存目录、写入数据,并返回路径型 artifact,避免大对象直接进入 MCP 响应。\n */\nexport async function writePerformanceArtifact(\n options: WritePerformanceArtifactOptions\n): Promise<PerformanceArtifact> {\n const root = resolve(options.root ?? process.cwd())\n const dir = resolveOutputDirectory(root, options.saveDir)\n const path = resolve(dir, createSafeFileName(options.fileName))\n const data = typeof options.data === 'string' ? Buffer.from(options.data) : options.data\n\n await mkdir(dir, { recursive: true })\n await writeFile(path, data)\n\n return {\n kind: options.kind,\n path,\n relativePath: relative(root, path),\n byteLength: data.byteLength,\n source: 'cdp'\n }\n}\n\n/**\n * 解析性能产物保存目录。\n *\n * 相对路径按项目根目录解析,绝对路径则原样保留,这样用户可以把重产物单独放到外部目录。\n */\nfunction resolveOutputDirectory(root: string, saveDir: string): string {\n return resolve(root, saveDir)\n}\n\n/**\n * 生成安全文件名。\n *\n * 文件名允许调用方提供前缀,但会补一个短随机后缀,避免同一毫秒内重复写入发生冲突。\n */\nfunction createSafeFileName(fileName: string): string {\n const trimmed = fileName.trim()\n\n if (!trimmed) {\n return `${String(Date.now())}-${nanoid()}`\n }\n\n const suffix = nanoid(6)\n const dotIndex = trimmed.lastIndexOf('.')\n\n if (dotIndex === -1) {\n return `${trimmed}-${suffix}`\n }\n\n const base = trimmed.slice(0, dotIndex)\n const extension = trimmed.slice(dotIndex)\n\n return `${base}-${suffix}${extension}`\n}\n","/**\n * CDP 性能采集。\n *\n * 该文件只处理浏览器调试协议可见的性能指标、CPU profile 和 heap snapshot,不承载 runtime 降级逻辑。\n */\nimport type CDP from 'chrome-remote-interface'\nimport {\n buildMemorySummary,\n buildPerformanceSummary,\n buildStackSummary\n} from '../performance/summary'\nimport { writePerformanceArtifact } from '../performance/output'\nimport type {\n LongTaskRecord,\n MemorySample,\n PerformanceArtifact,\n PerformanceReport,\n StackFrameSummary\n} from '../types'\n\n/**\n * CDP 性能采集参数。\n */\nexport interface CdpPerformanceOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 当前页面 id,用于输出产物命名和报告聚合。 */\n readonly pageId: string\n /** 采集窗口时长。 */\n readonly durationMs: number\n /** 是否采集内存。 */\n readonly includeMemory: boolean\n /** 是否采集可定位堆栈。 */\n readonly includeStacks: boolean\n /** 保存原始 profile 的目录,默认 `.vite-mcp/performance`。 */\n readonly saveDir?: string\n}\n\n/**\n * CDP 性能启动参数。\n *\n * start 阶段不需要采样窗口时长,只负责打开 profiler 并留下会话信息。\n */\nexport type CdpPerformanceStartOptions = Omit<CdpPerformanceOptions, 'durationMs'>\n\n/**\n * CDP 性能会话信息。\n *\n * 交互式录制需要在 start/stop 两次工具调用之间保持会话元数据,\n * 但不把裸 client 暴露给上层的 structuredContent。\n */\nexport interface CdpPerformanceSession {\n /** 录制 id。 */\n readonly recordingId: string\n /** 页面 id。 */\n readonly pageId: string\n /** 开始时间。 */\n readonly startedAt: number\n /** 是否采集内存。 */\n readonly includeMemory: boolean\n /** 是否采集堆栈。 */\n readonly includeStacks: boolean\n /** 保存目录。 */\n readonly saveDir?: string\n}\n\n/**\n * Heap snapshot 采集参数。\n */\nexport interface HeapSnapshotOptions {\n /** 已连接的 CDP client。 */\n readonly client: CDP.Client\n /** 当前页面 id,用于输出产物命名。 */\n readonly pageId: string\n /** 保存 heap snapshot 的目录。 */\n readonly saveDir: string\n}\n\n/**\n * CDP 的最小性能 metric 结构。\n */\ninterface CdpMetric {\n /** metric 名称。 */\n readonly name: string\n /** metric 值。 */\n readonly value: number\n}\n\n/**\n * CDP 性能 metric 返回值。\n */\ninterface CdpMetricsResult {\n readonly metrics: CdpMetric[]\n}\n\n/**\n * CDP CPU profile 结构。\n */\ninterface CdpCpuProfile {\n readonly nodes?: CdpCpuProfileNode[]\n readonly samples?: number[]\n readonly timeDeltas?: number[]\n}\n\n/**\n * CDP CPU profile stop 返回值。\n */\ninterface CdpProfileResult {\n readonly profile: CdpCpuProfile\n}\n\n/**\n * CPU profile 节点。\n */\ninterface CdpCpuProfileNode {\n readonly id: number\n readonly callFrame: {\n readonly functionName: string\n readonly url?: string\n readonly lineNumber?: number\n readonly columnNumber?: number\n }\n readonly hitCount?: number\n}\n\n/**\n * 使用 CDP 采集性能报告。\n */\nexport async function recordCdpPerformance(\n options: CdpPerformanceOptions\n): Promise<PerformanceReport> {\n const session = await startCdpPerformanceRecording(options)\n await waitForDuration(options.durationMs)\n return stopCdpPerformanceRecording({\n client: options.client,\n session\n })\n}\n\n/**\n * 开始一次 CDP 性能录制。\n */\nexport async function startCdpPerformanceRecording(\n options: CdpPerformanceStartOptions\n): Promise<CdpPerformanceSession> {\n await options.client.Performance.enable()\n await options.client.Profiler.enable()\n await options.client.Profiler.start()\n\n return {\n recordingId: createRecordingId(options.pageId),\n pageId: options.pageId,\n startedAt: Date.now(),\n includeMemory: options.includeMemory,\n includeStacks: options.includeStacks,\n saveDir: options.saveDir\n }\n}\n\n/**\n * 停止一次 CDP 性能录制并生成报告。\n */\nexport async function stopCdpPerformanceRecording(options: {\n readonly client: CDP.Client\n readonly session: CdpPerformanceSession\n}): Promise<PerformanceReport> {\n const endedAt = Date.now()\n const [metricsResult, profileResult] = await Promise.all([\n options.client.Performance.getMetrics() as Promise<CdpMetricsResult>,\n options.client.Profiler.stop() as Promise<CdpProfileResult>\n ])\n\n const metrics = toMetricMap(metricsResult.metrics)\n const longTasks = toLongTaskRecords(metrics)\n const memorySamples = options.session.includeMemory\n ? [toMemorySample(metrics)]\n : []\n const memory = options.session.includeMemory\n ? buildMemorySummary(memorySamples)\n : undefined\n const stacks = options.session.includeStacks\n ? buildStackSummary(aggregateCpuProfile(profileResult.profile))\n : undefined\n const artifact = await writeCpuProfileArtifact(\n {\n pageId: options.session.pageId,\n saveDir: options.session.saveDir\n },\n profileResult.profile\n )\n const report: PerformanceReport = {\n recordingId: options.session.recordingId,\n pageId: options.session.pageId,\n source: 'cdp',\n startedAt: options.session.startedAt,\n endedAt,\n durationMs: endedAt - options.session.startedAt,\n summary: buildPerformanceSummary({\n longTasks,\n memorySamples\n }),\n longTasks,\n memory,\n stacks,\n artifacts: [artifact],\n limitations: [\n 'CDP path returns sampled CPU profile data, not a full instruction trace'\n ]\n }\n\n return report\n}\n\n/**\n * 采集 heap snapshot 并返回路径型产物。\n */\nexport async function takeHeapSnapshot(\n options: HeapSnapshotOptions\n): Promise<PerformanceArtifact> {\n const chunks: string[] = []\n\n await options.client.HeapProfiler.enable()\n options.client.HeapProfiler.addHeapSnapshotChunk((event) => {\n const payload = event as { chunk?: string }\n if (payload.chunk) {\n chunks.push(payload.chunk)\n }\n })\n\n await options.client.HeapProfiler.takeHeapSnapshot({\n reportProgress: false\n })\n\n const artifact = await writePerformanceArtifact({\n root: process.cwd(),\n saveDir: options.saveDir,\n fileName: `${options.pageId}-heap-snapshot.heapsnapshot`,\n kind: 'heap-snapshot',\n data: Buffer.from(chunks.join(''))\n })\n\n return artifact\n}\n\n/**\n * 创建录制 id。\n */\nfunction createRecordingId(pageId: string): string {\n return `cdp-${pageId}-${String(Date.now())}`\n}\n\n/**\n * 等待指定时长。\n */\nfunction waitForDuration(durationMs: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve()\n }, durationMs)\n })\n}\n\n/**\n * 将 metrics 转成 map。\n */\nfunction toMetricMap(metrics: CdpMetric[]): Map<string, number> {\n return new Map(metrics.map((metric) => [metric.name, metric.value]))\n}\n\n/**\n * 将 CDP metrics 归一成 long task 记录。\n */\nfunction toLongTaskRecords(metrics: Map<string, number>): LongTaskRecord[] {\n const taskDuration = metrics.get('TaskDuration') ?? 0\n\n if (taskDuration <= 0) {\n return []\n }\n\n return [\n {\n startTime: 0,\n durationMs: taskDuration,\n name: 'TaskDuration',\n source: 'cpu-profile'\n }\n ]\n}\n\n/**\n * 将 metrics 归一成内存采样。\n */\nfunction toMemorySample(metrics: Map<string, number>): MemorySample {\n return {\n timestamp: Date.now(),\n usedJSHeapSize: metrics.get('JSHeapUsedSize'),\n totalJSHeapSize: metrics.get('JSHeapTotalSize'),\n jsHeapSizeLimit: metrics.get('JSHeapSizeLimit')\n }\n}\n\n/**\n * 聚合 CPU profile 热点。\n */\nfunction aggregateCpuProfile(profile: CdpCpuProfile): StackFrameSummary[] {\n const nodes = profile.nodes ?? []\n const nodeMap = new Map<number, AggregatedFrame>()\n const nodeIndex = new Map<number, CdpCpuProfileNode>()\n\n nodes.forEach((node) => nodeIndex.set(node.id, node))\n ;(profile.samples ?? []).forEach((nodeId, index) => {\n const node = nodeIndex.get(nodeId)\n if (!node) {\n return\n }\n\n const delta = profile.timeDeltas?.[index] ?? 0\n const current = nodeMap.get(nodeId) ?? {\n functionName: node.callFrame.functionName || '<anonymous>',\n url: node.callFrame.url,\n lineNumber: node.callFrame.lineNumber,\n columnNumber: node.callFrame.columnNumber,\n selfTimeMs: 0,\n totalTimeMs: 0,\n hitCount: 0\n }\n\n nodeMap.set(nodeId, {\n ...current,\n selfTimeMs: current.selfTimeMs + delta,\n totalTimeMs: current.totalTimeMs + delta,\n hitCount: current.hitCount + 1\n })\n })\n\n return [...nodeMap.values()]\n}\n\n/**\n * CDP 热点帧的内部累加结构。\n */\ninterface AggregatedFrame extends StackFrameSummary {\n selfTimeMs: number\n totalTimeMs: number\n hitCount: number\n}\n\n/**\n * 将 CPU profile 写成原始文件。\n */\nasync function writeCpuProfileArtifact(\n options: {\n readonly pageId: string\n readonly saveDir?: string\n },\n profile: CdpCpuProfile\n): Promise<PerformanceArtifact> {\n return writePerformanceArtifact({\n root: process.cwd(),\n saveDir: options.saveDir ?? '.vite-mcp/performance',\n fileName: `${options.pageId}-cpu-profile.cpuprofile`,\n kind: 'cpu-profile',\n data: Buffer.from(JSON.stringify(profile, null, 2))\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 inputSchema: {\n includeDisconnected: z.boolean().optional()\n }\n },\n async (input) => {\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 includeDisconnected: input.includeDisconnected\n }),\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","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\nimport { createCdpStorageAdapter } from '../../cdp/cdpStorage'\nimport { MCP_TOOL_NAMES } from '../../constants'\nimport type {\n RuntimeStorageRequest,\n StorageAction,\n StorageScope,\n VueMcpNextContext\n} from '../../types'\nimport {\n closeCdpClient,\n connectCdpForPage,\n createToolError,\n createToolResponse,\n requestRuntimeData,\n resolvePageTarget\n} from '../routeTools'\n\n/**\n * 注册浏览器存储相关 MCP 工具。\n *\n * 存储能力同时触及页面同源数据和浏览器级 Cookie,必须单独成组以便清晰表达 runtime 同源边界、\n * CDP 浏览器级能力,以及 HttpOnly Cookie 的只读/不可见限制。\n */\nexport function registerStorageTools(\n server: McpServer,\n ctx: VueMcpNextContext\n): void {\n registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {\n description: 'List same-origin storage and CDP cookies when available.',\n inputSchema: {\n pageId: z.string().optional()\n },\n action: 'list',\n handler: (input) => handleListStorage(ctx, input.pageId)\n })\n registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {\n description: 'Read one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'get',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'get' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {\n description: 'Write one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'set',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'set' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {\n description: 'Delete one storage entry.',\n inputSchema: createStorageInputSchema(),\n action: 'delete',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'delete' })\n })\n registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {\n description: 'Clear one storage scope.',\n inputSchema: createStorageInputSchema(),\n action: 'clear',\n handler: (input) => handleStorageAction(ctx, { ...input, action: 'clear' })\n })\n}\n\ninterface StorageToolInput {\n readonly pageId?: string\n readonly action: StorageAction\n readonly scope?: StorageScope\n readonly key?: string\n readonly value?: string\n readonly databaseName?: string\n readonly objectStoreName?: string\n readonly indexName?: string\n readonly cookie?: RuntimeStorageRequest['cookie']\n}\n\nfunction registerStorageTool<TInput extends z.ZodRawShape>(\n server: McpServer,\n name: string,\n options: {\n readonly description: string\n readonly inputSchema: TInput\n readonly action: StorageAction\n readonly handler: (input: z.infer<z.ZodObject<TInput>>) => Promise<unknown>\n }\n): void {\n server.registerTool(\n name,\n {\n description: options.description,\n inputSchema: options.inputSchema\n },\n (async (input: unknown) =>\n options.handler(\n input as z.infer<z.ZodObject<TInput>>\n )) as never\n )\n}\n\nfunction createStorageInputSchema() {\n return {\n pageId: z.string().optional(),\n scope: z\n .enum(['localStorage', 'sessionStorage', 'indexedDB', 'cookie'])\n .optional(),\n key: z.string().optional(),\n value: z.string().optional(),\n databaseName: z.string().optional(),\n objectStoreName: z.string().optional(),\n indexName: z.string().optional(),\n cookie: z\n .object({\n name: z.string(),\n value: z.string().optional(),\n domain: z.string().optional(),\n path: z.string().optional(),\n url: z.string().optional(),\n httpOnly: z.boolean().optional(),\n secure: z.boolean().optional(),\n sameSite: z.enum(['strict', 'lax', 'none']).optional(),\n expires: z.number().optional()\n })\n .optional()\n }\n}\n\n/**\n * 汇总当前页面可访问的同源存储,并附加 Cookie 概览。\n *\n * list_storage 面向排查场景,默认返回整体概览比单 scope 更符合使用预期;Cookie 在 CDP 可用时\n * 使用浏览器级查询,否则回退到 document.cookie 可见的同源 Cookie。\n */\nasync function handleListStorage(\n ctx: VueMcpNextContext,\n pageId?: string\n) {\n let baseRequest: RuntimeStorageRequest\n\n try {\n baseRequest = createStorageRequest(ctx, {\n pageId,\n action: 'list',\n scope: 'localStorage'\n })\n } catch (error) {\n return createToolError(error instanceof Error ? error.message : String(error))\n }\n\n const [localStorage, sessionStorage, indexedDB] = await Promise.all([\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'localStorage' }),\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'sessionStorage' }),\n requestRuntimeStorage(ctx, { ...baseRequest, scope: 'indexedDB' })\n ])\n const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId)\n\n return createToolResponse({\n ok: true,\n origin: baseRequest.origin,\n localStorage: extractStorageData(localStorage),\n sessionStorage: extractStorageData(sessionStorage),\n indexedDB: extractStorageData(indexedDB),\n cookie\n })\n}\n\n/**\n * 执行单个存储读写动作,并按 scope 选择 CDP 或运行时桥接。\n *\n * Cookie 属于浏览器级资源,必须走 CDP;IndexedDB 写入仍保留运行时桥接作为兜底,因为 CDP\n * 不提供通用的对象写入接口。\n */\nasync function handleStorageAction(\n ctx: VueMcpNextContext,\n input: StorageToolInput\n) {\n let request: RuntimeStorageRequest\n\n try {\n request = createStorageRequest(ctx, input)\n } catch (error) {\n return createToolError(error instanceof Error ? error.message : String(error))\n }\n\n const cdp = await connectCdpForPage(ctx, input.pageId)\n\n if (cdp && shouldUseCdpStorage(request)) {\n try {\n const result = await createCdpStorageAdapter(cdp.client).manageStorage(\n request\n )\n\n return createToolResponse(result)\n } finally {\n await closeCdpClient(cdp.client)\n }\n }\n\n const result = await requestRuntimeStorage(ctx, request)\n\n return createToolResponse(result)\n}\n\n/**\n * 通过页面运行时桥接访问同源存储。\n *\n * 该路径继承浏览器同源策略,适合 localStorage、sessionStorage 以及 IndexedDB 的页面级操作。\n */\nasync function requestRuntimeStorage(\n ctx: VueMcpNextContext,\n request: RuntimeStorageRequest\n): Promise<unknown> {\n return requestRuntimeData(ctx, (event) => {\n void ctx.rpcServer?.manageStorage({\n ...request,\n event\n })\n })\n}\n\n/**\n * 读取 Cookie 概览。\n *\n * CDP 可用时返回浏览器级 Cookie;否则回退到 runtime 可见 Cookie,避免无 CDP 环境下丢失\n * 当前页面同源 Cookie 的基础排查能力。\n */\nasync function listCookiesIfCdpAvailable(\n ctx: VueMcpNextContext,\n request: RuntimeStorageRequest,\n pageId?: string\n): Promise<unknown> {\n if (!hasCdpConfig(ctx)) {\n return extractStorageData(\n await requestRuntimeStorage(ctx, { ...request, scope: 'cookie' })\n )\n }\n\n const cdp = await connectCdpForPage(ctx, pageId)\n\n if (!cdp) {\n return extractStorageData(\n await requestRuntimeStorage(ctx, { ...request, scope: 'cookie' })\n )\n }\n\n try {\n const result = await createCdpStorageAdapter(cdp.client).manageStorage({\n ...request,\n scope: 'cookie'\n })\n\n return extractStorageData(result)\n } finally {\n await closeCdpClient(cdp.client)\n }\n}\n\n/**\n * 提取存储适配器的业务数据。\n *\n * MCP 工具对外只需要展示实际存储内容;保留原始结果作为异常形态兜底,便于测试和调试定位。\n */\nfunction extractStorageData(result: unknown): unknown {\n if (!isStorageResultRecord(result)) {\n return result\n }\n\n return result.data ?? result\n}\n\n/**\n * 判断结果是否符合存储适配器的基础结构。\n *\n * 这里仅检查 ok 字段,避免对不同 scope 的 data 形态做过度约束。\n */\nfunction isStorageResultRecord(\n value: unknown\n): value is { readonly data?: unknown } {\n return typeof value === 'object' && value !== null && 'ok' in value\n}\n\n/**\n * 判断单次存储操作是否应交给 CDP。\n *\n * Cookie 需要浏览器级权限,始终走 CDP;IndexedDB 属于页面同源存储,统一走 runtime 桥接,\n * 避免不同浏览器版本的 CDP IndexedDB 协议差异导致读取或删除卡住。\n */\nfunction shouldUseCdpStorage(request: RuntimeStorageRequest): boolean {\n return request.scope === 'cookie'\n}\n\nfunction createStorageRequest(\n ctx: VueMcpNextContext,\n input: StorageToolInput\n): RuntimeStorageRequest {\n const page = resolvePageTarget(ctx, input.pageId)\n const origin = new URL(page.url).origin\n\n return {\n event: '',\n pageId: page.pageId,\n origin,\n action: input.action,\n scope: normalizeScope(input.scope),\n key: input.key,\n value: input.value,\n databaseName: input.databaseName,\n objectStoreName: input.objectStoreName,\n indexName: input.indexName,\n cookie: input.cookie\n }\n}\n\nfunction normalizeScope(scope?: StorageScope): StorageScope {\n return scope ?? 'localStorage'\n}\n\nfunction hasCdpConfig(ctx: VueMcpNextContext): boolean {\n return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint)\n}\n","import type CDP from 'chrome-remote-interface'\nimport type { RuntimeStorageRequest, RuntimeStorageResult } from '../types'\n\n/**\n * CDP 存储适配器。\n *\n * Cookie 和部分 IndexedDB 能力需要浏览器协议权限;单独收敛在这里可以避免 MCP 工具层\n * 直接拼协议参数,也让 HttpOnly 删除限制集中审查。\n */\n\n/** CDP 存储适配器实例。 */\nexport interface CdpStorageAdapter {\n /** 根据统一存储请求调用 CDP 存储协议。 */\n manageStorage(request: RuntimeStorageRequest): Promise<RuntimeStorageResult>\n}\n\n/**\n * 创建 CDP 存储适配器。\n *\n * 调用方负责连接和关闭 CDP client,本适配器只执行单次存储操作。\n */\nexport function createCdpStorageAdapter(client: CDP.Client): CdpStorageAdapter {\n return {\n async manageStorage(request) {\n try {\n return await manageCdpStorage(client, request)\n } catch (error) {\n return createCdpStorageError(\n request,\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n }\n}\n\nasync function manageCdpStorage(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.scope === 'cookie') {\n return manageCdpCookies(client, request)\n }\n\n if (request.scope === 'indexedDB') {\n return manageCdpIndexedDb(client, request)\n }\n\n return manageCdpDomStorage(client, request)\n}\n\nasync function manageCdpCookies(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.action === 'list' || request.action === 'get') {\n const result = await client.Storage.getCookies()\n const cookies = result.cookies.filter((cookie) =>\n isCookieInOrigin(cookie, request.origin)\n )\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n cookies:\n request.action === 'get' && request.cookie?.name\n ? cookies.filter((cookie) => cookie.name === request.cookie?.name)\n : cookies\n })\n }\n\n if (request.action === 'set') {\n if (!request.cookie?.name) {\n throw new Error('Cookie name is required for set operation')\n }\n\n await client.Storage.setCookies({\n cookies: [\n {\n name: request.cookie.name,\n value: request.cookie.value ?? request.value ?? '',\n url: request.cookie.url ?? request.origin,\n domain: request.cookie.domain,\n path: request.cookie.path,\n httpOnly: request.cookie.httpOnly,\n secure: request.cookie.secure,\n sameSite: normalizeCookieSameSite(request.cookie.sameSite),\n expires: request.cookie.expires\n }\n ]\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n const result = await client.Storage.getCookies()\n const cookies = result.cookies.filter((cookie) =>\n isCookieInOrigin(cookie, request.origin)\n )\n const candidates =\n request.action === 'delete' && request.cookie?.name\n ? cookies.filter((cookie) => cookie.name === request.cookie?.name)\n : cookies\n const deletable = candidates.filter((cookie) => !cookie.httpOnly)\n const skippedHttpOnlyCount = candidates.length - deletable.length\n\n for (const cookie of deletable) {\n await client.Network.deleteCookies({\n name: cookie.name,\n domain: cookie.domain,\n path: cookie.path\n })\n }\n\n return createCdpStorageSuccess(request, {\n deletedCount: deletable.length,\n skippedHttpOnlyCount\n })\n}\n\nasync function manageCdpDomStorage(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n const storageId = {\n securityOrigin: request.origin,\n isLocalStorage: request.scope === 'localStorage'\n }\n\n if (request.action === 'list') {\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n entries: result.entries.map(([key, value]) => ({ key, value }))\n })\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n const entry = result.entries.find(([key]) => key === request.key)\n\n return createCdpStorageSuccess(request, {\n key: request.key,\n value: entry?.[1] ?? null\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n await client.DOMStorage.setDOMStorageItem({\n storageId,\n key: request.key,\n value: request.value ?? ''\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n await client.DOMStorage.removeDOMStorageItem({\n storageId,\n key: request.key\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n const result = await client.DOMStorage.getDOMStorageItems({ storageId })\n\n for (const [key] of result.entries) {\n await client.DOMStorage.removeDOMStorageItem({ storageId, key })\n }\n\n return createCdpStorageSuccess(request, { deletedCount: result.entries.length })\n}\n\nasync function manageCdpIndexedDb(\n client: CDP.Client,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.action === 'list') {\n const result = await client.IndexedDB.requestDatabaseNames({\n securityOrigin: request.origin\n })\n\n return createCdpStorageSuccess(request, {\n origin: request.origin,\n databases: result.databaseNames\n })\n }\n\n assertIndexedDbTarget(request)\n\n if (request.action === 'get') {\n const result = await client.IndexedDB.requestData({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n indexName: request.indexName ?? '',\n skipCount: 0,\n pageSize: 100\n })\n\n return createCdpStorageSuccess(request, {\n entries: result.objectStoreDataEntries,\n hasMore: result.hasMore\n })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n await client.IndexedDB.deleteObjectStoreEntries({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n keyRange: createExactCdpKeyRange(request.key) as never\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'clear') {\n if (request.objectStoreName) {\n await client.IndexedDB.clearObjectStore({\n securityOrigin: request.origin,\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n await client.IndexedDB.deleteDatabase({\n securityOrigin: request.origin,\n databaseName: request.databaseName\n })\n\n return createCdpStorageSuccess(request, { ok: true })\n }\n\n return createCdpStorageError(\n request,\n 'IndexedDB set operation requires runtime bridge'\n )\n}\n\nfunction isCookieInOrigin(\n cookie: { readonly domain?: string },\n origin: string\n): boolean {\n const hostname = new URL(origin).hostname\n const domain = cookie.domain?.replace(/^\\./, '')\n\n return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)))\n}\n\nfunction normalizeCookieSameSite(\n sameSite?: 'strict' | 'lax' | 'none'\n): 'Strict' | 'Lax' | 'None' | undefined {\n if (!sameSite) {\n return undefined\n }\n\n if (sameSite === 'strict') {\n return 'Strict'\n }\n\n if (sameSite === 'lax') {\n return 'Lax'\n }\n\n return 'None'\n}\n\nfunction createExactCdpKeyRange(key: string): {\n readonly lower: unknown\n readonly upper: unknown\n readonly lowerOpen: boolean\n readonly upperOpen: boolean\n} {\n const parsedKey = parseJsonValue(key)\n\n return {\n lower: parsedKey,\n upper: parsedKey,\n lowerOpen: false,\n upperOpen: false\n }\n}\n\nfunction parseJsonValue(value: string): unknown {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n}\n\nfunction assertStorageKey(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & { readonly key: string } {\n if (!request.key) {\n throw new Error('Storage key is required for this operation')\n }\n}\n\nfunction assertIndexedDbTarget(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n} {\n if (!request.databaseName || !request.objectStoreName) {\n throw new Error('IndexedDB databaseName and objectStoreName are required')\n }\n}\n\nfunction createCdpStorageSuccess(\n request: RuntimeStorageRequest,\n data: unknown\n): RuntimeStorageResult {\n return {\n ok: true,\n source: 'cdp',\n action: request.action,\n scope: request.scope,\n data\n }\n}\n\nfunction createCdpStorageError(\n request: RuntimeStorageRequest,\n error: string\n): RuntimeStorageResult {\n return {\n ok: false,\n source: 'cdp',\n action: request.action,\n scope: request.scope,\n error\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 getElementContext: () => undefined,\n onElementContextUpdated: (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 manageStorage: () => undefined,\n onStorageUpdated: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n recordPerformance: () => undefined,\n onPerformanceRecorded: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n startPerformanceRecording: () => undefined,\n onPerformanceRecordingStarted: (event, data) => {\n void ctx.hooks.callHook(event, data)\n },\n stopPerformanceRecording: () => undefined,\n onPerformanceRecordingStopped: (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 * 共享序列化工具负责把运行时对象转换成可跨 RPC、日志和 MCP hooks 传输的数据。\n *\n * 这里不能直接依赖 `JSON.stringify()` 处理未知对象,因为 DevTools、Vue reactive 或 birpc Proxy\n * 可能在读取 `toJSON` 时触发副作用,导致序列化阶段抛出远端函数不存在的错误。\n */\n\n/** RPC 可安全传输的数据形态,限制为 JSON 兼容的基础类型、数组和普通对象。 */\nexport type RpcSafeValue =\n | string\n | number\n | boolean\n | null\n | RpcSafeValue[]\n | { [key: string]: RpcSafeValue }\n\n/** 循环引用降级值,用于保留结构问题而不是中断整个 MCP 请求。 */\nconst RPC_CIRCULAR_VALUE = '[Circular]'\n\n/** 不可读取字段的降级值,用于隔离 getter 或 Proxy 读取异常。 */\nconst RPC_UNREADABLE_VALUE = '[Unreadable]'\n\n/**\n * 把未知运行时值转换为 RPC 安全快照。\n *\n * 该函数只读取自有可枚举字符串键,显式跳过 `toJSON`,适用于 Vue DevTools 返回值进入\n * `vite-dev-rpc` 之前的边界清洗。对象字段中的不可传输值会被省略,数组项则降级为 `null`,\n * 这样可以同时保持对象语义和数组下标稳定。\n */\nexport function toRpcSafeValue(value: unknown): RpcSafeValue | undefined {\n return toRpcSafeChildValue(value, new WeakSet(), false)\n}\n\n/**\n * 把任意值序列化成字符串。\n *\n * Console 和 CDP 记录只需要可读字符串,因此先复用 `toRpcSafeValue()` 去掉危险对象,\n * 再交给 JSON 序列化,避免历史上循环引用或 `toJSON` 副作用破坏日志采集。\n */\nexport function safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value\n }\n\n const safeValue = toRpcSafeValue(value)\n return safeValue === undefined ? 'undefined' : JSON.stringify(safeValue)\n}\n\n/**\n * 按上下文转换子值。\n *\n * `arrayItem` 用于区分对象字段和数组项:对象字段可以省略不可传输值,数组项必须保留位置,\n * 因此使用 `null` 作为降级值。\n */\nfunction toRpcSafeChildValue(\n value: unknown,\n seen: WeakSet<object>,\n arrayItem: boolean\n): RpcSafeValue | undefined {\n if (value === null) {\n return null\n }\n\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return value\n case 'number':\n return Number.isFinite(value) ? value : String(value)\n case 'bigint':\n return value.toString()\n case 'symbol':\n return toSymbolPlaceholder(value)\n case 'undefined':\n case 'function':\n return arrayItem ? null : undefined\n case 'object':\n return toRpcSafeObject(value, seen)\n default:\n return arrayItem ? null : undefined\n }\n}\n\n/**\n * 转换对象值,并用 `seen` 识别当前递归路径中的循环引用。\n *\n * `seen` 在函数退出时删除当前对象,避免把同一个对象在兄弟字段中的重复引用误判为循环。\n */\nfunction toRpcSafeObject(\n value: object,\n seen: WeakSet<object>\n): RpcSafeValue {\n if (seen.has(value)) {\n return RPC_CIRCULAR_VALUE\n }\n\n seen.add(value)\n try {\n if (value instanceof Date) {\n return toSafeDate(value)\n }\n\n if (value instanceof Error) {\n return toSafeError(value, seen)\n }\n\n if (Array.isArray(value)) {\n return toSafeArray(value, seen)\n }\n\n return toSafeRecord(value, seen)\n } finally {\n seen.delete(value)\n }\n}\n\n/**\n * 转换数组并保留下标稳定性。\n *\n * 数组里的函数、`undefined` 等不可传输项会变成 `null`,避免调用方根据下标读取 children\n * 或 state entries 时出现位置错位。\n */\nfunction toSafeArray(values: unknown[], seen: WeakSet<object>): RpcSafeValue[] {\n return values.map((item) => toRpcSafeChildValue(item, seen, true) ?? null)\n}\n\n/**\n * 转换普通对象或带可枚举字段的 class-like 对象。\n *\n * 只遍历 `Object.keys()` 返回的字符串键,不读取原型链和 symbol key;`toJSON` 会被跳过,\n * 因为读取它没有业务价值,且正是 birpc Proxy 常见的误触发入口。\n */\nfunction toSafeRecord(value: object, seen: WeakSet<object>): RpcSafeValue {\n const keys = getEnumerableKeys(value)\n if (!keys) {\n return RPC_UNREADABLE_VALUE\n }\n\n if (keys.length === 0 && !isPlainRecord(value)) {\n return toObjectSummary(value)\n }\n\n const result: { [key: string]: RpcSafeValue } = {}\n keys.forEach((key) => {\n if (key === 'toJSON') {\n return\n }\n\n const field = readObjectField(value, key)\n if (!field.ok) {\n result[key] = RPC_UNREADABLE_VALUE\n return\n }\n\n const safeValue = toRpcSafeChildValue(field.value, seen, false)\n if (safeValue !== undefined) {\n result[key] = safeValue\n }\n })\n\n return result\n}\n\n/**\n * 转换错误对象的关键诊断字段。\n *\n * Error 的 `message` 和 `stack` 通常不可枚举,单纯走 `Object.keys()` 会丢失排障信息,\n * 因此这里显式读取,同时仍然保护 `cause` 这类可能携带复杂对象的字段。\n */\nfunction toSafeError(error: Error, seen: WeakSet<object>): RpcSafeValue {\n const result: { [key: string]: RpcSafeValue } = {\n name: error.name,\n message: error.message\n }\n\n const stack = readObjectField(error, 'stack')\n if (stack.ok && typeof stack.value === 'string') {\n result.stack = stack.value\n }\n\n if ('cause' in error) {\n const cause = readObjectField(error, 'cause')\n result.cause = cause.ok\n ? toRpcSafeChildValue(cause.value, seen, false) ?? null\n : RPC_UNREADABLE_VALUE\n }\n\n return result\n}\n\n/**\n * 转换 Date,避免调用 `Date.prototype.toJSON()`。\n *\n * `toISOString()` 不走 `toJSON`,并且无效日期用固定字符串表达,避免异常穿透 RPC 边界。\n */\nfunction toSafeDate(value: Date): string {\n return Number.isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString()\n}\n\n/**\n * 安全读取对象的可枚举 key。\n *\n * Proxy 的 `ownKeys` 或 descriptor trap 可能抛错,调用方需要把整个对象降级为不可读。\n */\nfunction getEnumerableKeys(value: object): string[] | undefined {\n try {\n return Object.keys(value)\n } catch {\n return undefined\n }\n}\n\n/**\n * 安全读取单个字段。\n *\n * Vue reactive、getter 或 Proxy 都可能在字段读取时抛错;这里把错误收敛成结构化状态,\n * 让上层只降级当前字段。\n */\nfunction readObjectField(\n value: object,\n key: string\n): { ok: true; value: unknown } | { ok: false } {\n try {\n return {\n ok: true,\n value: (value as Record<string, unknown>)[key]\n }\n } catch {\n return { ok: false }\n }\n}\n\n/**\n * 判断对象是否是普通记录。\n *\n * 非普通对象如果没有可枚举字段,返回摘要比返回 `{}` 更有排障价值;普通空对象则保留 `{}`。\n */\nfunction isPlainRecord(value: object): boolean {\n try {\n const prototype: unknown = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n } catch {\n return false\n }\n}\n\n/**\n * 生成不可枚举对象的摘要。\n *\n * 摘要只用于兜底展示,不承诺可以还原原始对象。\n */\nfunction toObjectSummary(value: object): string {\n try {\n return Object.prototype.toString.call(value)\n } catch {\n return '[Object]'\n }\n}\n\n/**\n * 生成 symbol 占位值。\n *\n * Symbol 无法跨 RPC 保真,保留 description 可以帮助调试来源。\n */\nfunction toSymbolPlaceholder(value: symbol): string {\n return value.description ? `[Symbol(${value.description})]` : '[Symbol]'\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","/**\n * Vue SFC 元素标识注入。\n *\n * 该模块只在 Vite dev transform 阶段处理项目源码,把稳定、可读的\n * `data-v-mcp-id` 写到模板元素上;runtime 和 MCP 依赖这个 ID 建立\n * “用户点击 DOM -> AI 定位源码”的协作链路。\n */\n\nimport { parse } from '@vue/compiler-sfc'\nimport MagicString from 'magic-string'\nimport { relative } from 'node:path'\nimport type { TransformResult } from 'vite'\n\nconst VUE_FILE_SUFFIX = '.vue'\nconst ELEMENT_NODE_TYPE = 1\nconst SKIPPED_TAGS = new Set(['template', 'slot', 'script', 'style'])\nconst MCP_ID_ATTR = 'data-v-mcp-id'\n\n/**\n * 元素注入控制器。\n *\n * 返回 `undefined` 表示当前模块不适合注入,Vite 可继续走后续插件。\n */\nexport interface ElementInstrumentationController {\n transform(\n code: string,\n id: string,\n ssr?: boolean\n ): TransformResult | undefined\n}\n\n/**\n * 元素注入控制器配置。\n *\n * root 用于生成项目相对路径,避免把用户机器绝对路径暴露给 AI。\n */\nexport interface ElementInstrumentationOptions {\n readonly root: string\n}\n\ninterface TemplateAstNode {\n readonly type: number\n readonly tag?: string\n readonly loc?: {\n readonly start: {\n readonly line: number\n readonly column: number\n readonly offset: number\n }\n }\n readonly props?: readonly unknown[]\n readonly children?: readonly TemplateAstNode[]\n}\n\n/**\n * 创建元素标识注入控制器。\n *\n * 该控制器只处理本地开发态的项目源码,第三方依赖和虚拟模块必须跳过,\n * 避免把调试属性写入外部包产物或 Vite 内部虚拟模块。\n */\nexport function createElementInstrumentationController(\n options: ElementInstrumentationOptions\n): ElementInstrumentationController {\n return {\n transform(code, id, ssr) {\n if (ssr || shouldSkipInstrumentation(id)) {\n return undefined\n }\n\n const filename = id.split('?', 1)[0]\n\n if (!filename.endsWith(VUE_FILE_SUFFIX)) {\n return undefined\n }\n\n const parsed = parse(code, { filename })\n const template = parsed.descriptor.template\n\n if (!template?.ast) {\n return undefined\n }\n\n const s = new MagicString(code)\n const relativeFile = normalizePath(relative(options.root, filename))\n\n for (const node of template.ast.children) {\n injectNodeId(s, node as TemplateAstNode, relativeFile)\n }\n\n if (!s.hasChanged()) {\n return undefined\n }\n\n return {\n code: s.toString(),\n map: s.generateMap({ hires: true }) as TransformResult extends {\n map?: infer T\n }\n ? T\n : never\n }\n }\n }\n}\n\n/**\n * 判断当前 Vite 模块是否需要跳过注入。\n *\n * 过滤虚拟模块和 `node_modules` 是为了把源码定位限定在用户项目内;\n * SSR transform 由调用方传入,避免服务端渲染路径携带浏览器调试属性。\n */\nfunction shouldSkipInstrumentation(id: string): boolean {\n if (id.startsWith('\\0')) {\n return true\n }\n\n const normalized = normalizePath(id)\n\n if (normalized.includes('/node_modules/')) {\n return true\n }\n\n return !normalized.startsWith('/') && !/^[A-Za-z]:\\//.test(normalized)\n}\n\n/**\n * 统一路径分隔符。\n *\n * elementId 会被用户复制给 AI,跨平台场景下必须固定为 `/` 才便于解析。\n */\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\n/**\n * 递归给模板元素注入源码 ID。\n *\n * Vue 编译器的位置信息已经是源码中的行列号,因此这里不重新计算 offset;\n * 对已有 `data-v-mcp-id` 的元素保持尊重,方便项目手动覆盖或测试固定 ID。\n */\nfunction injectNodeId(\n s: MagicString,\n node: TemplateAstNode,\n relativeFile: string\n): void {\n if (node.type !== ELEMENT_NODE_TYPE || !node.tag || !node.loc) {\n return\n }\n\n if (!SKIPPED_TAGS.has(node.tag) && !hasMcpIdAttr(node)) {\n const id = `${relativeFile}:${String(node.loc.start.line)}:${String(node.loc.start.column)}`\n const insertAt = node.loc.start.offset + node.tag.length + 1\n s.appendLeft(insertAt, ` ${MCP_ID_ATTR}=\"${id}\"`)\n }\n\n for (const child of node.children ?? []) {\n injectNodeId(s, child, relativeFile)\n }\n}\n\n/**\n * 判断模板元素是否已经声明 MCP ID。\n *\n * 通过编译器 props 判断比字符串扫描更稳,避免被文本内容里的同名字符串误判。\n */\nfunction hasMcpIdAttr(node: TemplateAstNode): boolean {\n return (node.props ?? []).some((prop) => {\n if (!isTemplateProp(prop)) {\n return false\n }\n\n return prop.name === MCP_ID_ATTR\n })\n}\n\n/**\n * 收窄 Vue 编译器 prop 节点。\n *\n * 这里故意只读取 `name`,不依赖完整内部类型,减少后续 Vue 编译器小版本变更的影响面。\n */\nfunction isTemplateProp(value: unknown): value is { readonly name?: string } {\n return Boolean(value && typeof value === 'object' && 'name' in value)\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(options, getConfig()?.root)\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(\n options: ResolvedVueMcpNextOptions,\n root?: string\n): 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(${JSON.stringify({\n elementPicker: options.elementPicker,\n projectRoot: root\n })});`\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":["resolve","z","z","snapshot","nodes","z","z","z","z","z","z","z","nanoid","path","resolve","z","z","relative","z","resolve","z","result","cookies","z","result","hasCdpConfig","z","mkdir","writeFile","path","z","isPlainRecord","nanoid","z","z","path","nanoid","resolve","nanoid","isPlainRecord","nanoid","nanoid","nanoid","relative","normalizePath","path","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","isPerformanceReport"]}