@xiaou66/vite-plugin-vue-mcp-next 1.1.1 → 1.3.0

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.cjs CHANGED
@@ -72,6 +72,11 @@ var MCP_TOOL_NAMES = {
72
72
  getNetworkRequests: "get_network_requests",
73
73
  getNetworkRequestDetail: "get_network_request_detail",
74
74
  clearNetworkRequests: "clear_network_requests",
75
+ listStorage: "list_storage",
76
+ getStorageItem: "get_storage_item",
77
+ setStorageItem: "set_storage_item",
78
+ deleteStorageItem: "delete_storage_item",
79
+ clearStorage: "clear_storage",
75
80
  recordPerformance: "record_performance",
76
81
  startPerformanceRecording: "start_performance_recording",
77
82
  stopPerformanceRecording: "stop_performance_recording",
@@ -83,7 +88,8 @@ var MCP_TOOL_NAMES = {
83
88
  highlightComponent: "highlight_component",
84
89
  getRouterInfo: "get_router_info",
85
90
  getPiniaTree: "get_pinia_tree",
86
- getPiniaState: "get_pinia_state"
91
+ getPiniaState: "get_pinia_state",
92
+ getElementContext: "get_element_context"
87
93
  };
88
94
  var VIRTUAL_RUNTIME_ID = "virtual:vite-plugin-vue-mcp-next/runtime";
89
95
  var RESOLVED_VIRTUAL_RUNTIME_ID = `\0${VIRTUAL_RUNTIME_ID}`;
@@ -99,6 +105,7 @@ var RUNTIME_PAGE_DISCONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-disconnecte
99
105
  var RUNTIME_PAGE_HEARTBEAT_EVENT = "vite-plugin-vue-mcp-next:heartbeat";
100
106
  var DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45e3;
101
107
  var DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45e3;
108
+ var DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS = 2200;
102
109
  var DEFAULT_OPTIONS = {
103
110
  mcpPath: DEFAULT_MCP_PATH,
104
111
  host: "localhost",
@@ -117,6 +124,16 @@ var DEFAULT_OPTIONS = {
117
124
  skill: {
118
125
  autoConfig: true
119
126
  },
127
+ elementPicker: {
128
+ enabled: true,
129
+ shortcut: {
130
+ altKey: true,
131
+ shiftKey: true,
132
+ metaKey: false,
133
+ ctrlKey: false
134
+ },
135
+ toastDurationMs: DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS
136
+ },
120
137
  runtime: {
121
138
  mode: "auto",
122
139
  evaluate: {
@@ -191,6 +208,14 @@ function mergeOptions(options = {}) {
191
208
  ...DEFAULT_OPTIONS.skill,
192
209
  ...options.skill
193
210
  },
211
+ elementPicker: {
212
+ ...DEFAULT_OPTIONS.elementPicker,
213
+ ...options.elementPicker,
214
+ shortcut: {
215
+ ...DEFAULT_OPTIONS.elementPicker.shortcut,
216
+ ...options.elementPicker?.shortcut
217
+ }
218
+ },
194
219
  runtime: {
195
220
  ...DEFAULT_OPTIONS.runtime,
196
221
  ...options.runtime,
@@ -611,9 +636,164 @@ function registerDomTools(server, ctx) {
611
636
  );
612
637
  }
613
638
 
614
- // src/mcp/tools/evaluate.ts
639
+ // src/mcp/tools/elementContext.ts
615
640
  var import_zod3 = require("zod");
616
641
 
642
+ // src/shared/elementId.ts
643
+ var PROJECT_SOURCE_ID_PATTERN = /^(.+\.(?:vue|tsx|jsx|ts|js)):(\d+):(\d+)$/;
644
+ var RUNTIME_ID_PATTERN = /^runtime:([A-Za-z0-9_-]+)$/;
645
+ var PACKAGE_ID_PREFIX = "pkg:";
646
+ function parseElementId(elementId) {
647
+ const sourceMatch = PROJECT_SOURCE_ID_PATTERN.exec(elementId);
648
+ if (sourceMatch) {
649
+ return {
650
+ kind: "project-source",
651
+ elementId,
652
+ file: sourceMatch[1],
653
+ line: Number(sourceMatch[2]),
654
+ column: Number(sourceMatch[3])
655
+ };
656
+ }
657
+ if (elementId.startsWith(PACKAGE_ID_PREFIX)) {
658
+ return parsePackageElementId(elementId);
659
+ }
660
+ const runtimeMatch = RUNTIME_ID_PATTERN.exec(elementId);
661
+ if (runtimeMatch) {
662
+ return {
663
+ kind: "runtime",
664
+ elementId,
665
+ runtimeId: runtimeMatch[1]
666
+ };
667
+ }
668
+ return {
669
+ kind: "invalid",
670
+ elementId,
671
+ reason: "unsupported elementId format"
672
+ };
673
+ }
674
+ function parsePackageElementId(elementId) {
675
+ const value = elementId.slice(PACKAGE_ID_PREFIX.length);
676
+ const parts = value.split("/").filter(Boolean);
677
+ if (parts.length < 2) {
678
+ return {
679
+ kind: "invalid",
680
+ elementId,
681
+ reason: "package elementId must include packageName and entryFile"
682
+ };
683
+ }
684
+ const scoped = parts[0]?.startsWith("@");
685
+ const packageName = scoped ? parts.slice(0, 2).join("/") : parts[0];
686
+ const entryFile = parts.slice(scoped ? 2 : 1).join("/");
687
+ if (!entryFile) {
688
+ return {
689
+ kind: "invalid",
690
+ elementId,
691
+ reason: "package elementId must include entryFile"
692
+ };
693
+ }
694
+ return {
695
+ kind: "package",
696
+ elementId,
697
+ packageName,
698
+ entryFile
699
+ };
700
+ }
701
+
702
+ // src/mcp/tools/elementContext.ts
703
+ function registerElementContextTools(server, ctx) {
704
+ server.registerTool(
705
+ MCP_TOOL_NAMES.getElementContext,
706
+ {
707
+ description: "Get editable source, Vue component, and DOM context for a copied elementId.",
708
+ inputSchema: {
709
+ elementId: import_zod3.z.string(),
710
+ pageId: import_zod3.z.string().optional()
711
+ }
712
+ },
713
+ async (input) => {
714
+ const runtimeResult = await tryRuntimeElementContext(
715
+ ctx,
716
+ input.elementId,
717
+ input.pageId
718
+ );
719
+ if (runtimeResult) {
720
+ return createToolResponse(runtimeResult);
721
+ }
722
+ return createToolResponse(createStaticElementContext(input.elementId));
723
+ }
724
+ );
725
+ }
726
+ async function tryRuntimeElementContext(ctx, elementId, pageId) {
727
+ if (!ctx.rpcServer) {
728
+ return parseElementId(elementId).kind === "runtime" ? createRuntimeUnavailableContext(elementId) : void 0;
729
+ }
730
+ try {
731
+ resolvePageTarget(ctx, pageId);
732
+ } catch (error) {
733
+ const parsed = parseElementId(elementId);
734
+ if (parsed.kind === "project-source" || parsed.kind === "package") {
735
+ return void 0;
736
+ }
737
+ return {
738
+ ok: false,
739
+ elementId,
740
+ error: error instanceof Error ? error.message : String(error),
741
+ limitations: ["call list_pages and pass pageId when multiple pages exist"]
742
+ };
743
+ }
744
+ return await requestRuntimeData(ctx, (event) => {
745
+ void ctx.rpcServer?.getElementContext({ event, elementId });
746
+ });
747
+ }
748
+ function createStaticElementContext(elementId) {
749
+ const parsed = parseElementId(elementId);
750
+ if (parsed.kind === "project-source") {
751
+ return {
752
+ ok: true,
753
+ elementId,
754
+ editable: true,
755
+ codeLocation: {
756
+ file: parsed.file,
757
+ line: parsed.line,
758
+ column: parsed.column
759
+ },
760
+ limitations: ["runtime unavailable, DOM and component context omitted"]
761
+ };
762
+ }
763
+ if (parsed.kind === "package") {
764
+ return {
765
+ ok: true,
766
+ elementId,
767
+ editable: false,
768
+ packageLocation: {
769
+ packageName: parsed.packageName,
770
+ entryFile: parsed.entryFile
771
+ },
772
+ limitations: ["third-party package source is not editable from this project"]
773
+ };
774
+ }
775
+ if (parsed.kind === "runtime") {
776
+ return createRuntimeUnavailableContext(elementId);
777
+ }
778
+ return {
779
+ ok: false,
780
+ elementId,
781
+ error: parsed.reason,
782
+ limitations: ["please provide a copied elementId from the element picker"]
783
+ };
784
+ }
785
+ function createRuntimeUnavailableContext(elementId) {
786
+ return {
787
+ ok: false,
788
+ elementId,
789
+ error: "runtime bridge is not connected",
790
+ limitations: ["runtime ids are only valid while the page is connected"]
791
+ };
792
+ }
793
+
794
+ // src/mcp/tools/evaluate.ts
795
+ var import_zod4 = require("zod");
796
+
617
797
  // src/cdp/cdpEvaluate.ts
618
798
  async function cdpEvaluate(options) {
619
799
  const result = await options.client.Runtime.evaluate({
@@ -634,9 +814,9 @@ function registerEvaluateTools(server, ctx) {
634
814
  {
635
815
  description: "Evaluate a script in the selected page when explicitly enabled.",
636
816
  inputSchema: {
637
- pageId: import_zod3.z.string().optional(),
638
- expression: import_zod3.z.string(),
639
- awaitPromise: import_zod3.z.boolean().optional()
817
+ pageId: import_zod4.z.string().optional(),
818
+ expression: import_zod4.z.string(),
819
+ awaitPromise: import_zod4.z.boolean().optional()
640
820
  }
641
821
  },
642
822
  async (input) => {
@@ -685,18 +865,18 @@ function assertEvaluateEnabled(options) {
685
865
  }
686
866
 
687
867
  // src/mcp/tools/network.ts
688
- var import_zod4 = require("zod");
868
+ var import_zod5 = require("zod");
689
869
  function registerNetworkTools(server, ctx) {
690
870
  server.registerTool(
691
871
  MCP_TOOL_NAMES.getNetworkRequests,
692
872
  {
693
873
  description: "Get captured network request summaries.",
694
874
  inputSchema: {
695
- pageId: import_zod4.z.string().optional(),
696
- urlContains: import_zod4.z.string().optional(),
697
- method: import_zod4.z.string().optional(),
698
- status: import_zod4.z.number().optional(),
699
- limit: import_zod4.z.number().optional()
875
+ pageId: import_zod5.z.string().optional(),
876
+ urlContains: import_zod5.z.string().optional(),
877
+ method: import_zod5.z.string().optional(),
878
+ status: import_zod5.z.number().optional(),
879
+ limit: import_zod5.z.number().optional()
700
880
  }
701
881
  },
702
882
  (input) => {
@@ -719,7 +899,7 @@ function registerNetworkTools(server, ctx) {
719
899
  MCP_TOOL_NAMES.getNetworkRequestDetail,
720
900
  {
721
901
  description: "Get captured network request detail by id.",
722
- inputSchema: { id: import_zod4.z.string() }
902
+ inputSchema: { id: import_zod5.z.string() }
723
903
  },
724
904
  (input) => {
725
905
  if (ctx.options.network.mode === "off") {
@@ -736,7 +916,7 @@ function registerNetworkTools(server, ctx) {
736
916
  {
737
917
  description: "Clear cached network requests.",
738
918
  inputSchema: {
739
- pageId: import_zod4.z.string().optional()
919
+ pageId: import_zod5.z.string().optional()
740
920
  }
741
921
  },
742
922
  () => {
@@ -747,7 +927,7 @@ function registerNetworkTools(server, ctx) {
747
927
  }
748
928
 
749
929
  // src/mcp/tools/performance.ts
750
- var import_zod5 = require("zod");
930
+ var import_zod6 = require("zod");
751
931
 
752
932
  // src/performance/summary.ts
753
933
  function buildPerformanceSummary(input) {
@@ -1029,10 +1209,10 @@ function registerPerformanceTools(server, ctx) {
1029
1209
  {
1030
1210
  description: "Record a performance sample for the selected page.",
1031
1211
  inputSchema: {
1032
- pageId: import_zod5.z.string().optional(),
1033
- durationMs: import_zod5.z.number().optional(),
1034
- includeMemory: import_zod5.z.boolean().optional(),
1035
- includeStacks: import_zod5.z.boolean().optional()
1212
+ pageId: import_zod6.z.string().optional(),
1213
+ durationMs: import_zod6.z.number().optional(),
1214
+ includeMemory: import_zod6.z.boolean().optional(),
1215
+ includeStacks: import_zod6.z.boolean().optional()
1036
1216
  }
1037
1217
  },
1038
1218
  async (input) => handleRecordPerformance(ctx, input)
@@ -1042,9 +1222,9 @@ function registerPerformanceTools(server, ctx) {
1042
1222
  {
1043
1223
  description: "Start a performance recording session.",
1044
1224
  inputSchema: {
1045
- pageId: import_zod5.z.string().optional(),
1046
- includeMemory: import_zod5.z.boolean().optional(),
1047
- includeStacks: import_zod5.z.boolean().optional()
1225
+ pageId: import_zod6.z.string().optional(),
1226
+ includeMemory: import_zod6.z.boolean().optional(),
1227
+ includeStacks: import_zod6.z.boolean().optional()
1048
1228
  }
1049
1229
  },
1050
1230
  async (input) => handleStartPerformanceRecording(ctx, input)
@@ -1054,7 +1234,7 @@ function registerPerformanceTools(server, ctx) {
1054
1234
  {
1055
1235
  description: "Stop a performance recording session.",
1056
1236
  inputSchema: {
1057
- recordingId: import_zod5.z.string()
1237
+ recordingId: import_zod6.z.string()
1058
1238
  }
1059
1239
  },
1060
1240
  async (input) => handleStopPerformanceRecording(ctx, input)
@@ -1064,9 +1244,9 @@ function registerPerformanceTools(server, ctx) {
1064
1244
  {
1065
1245
  description: "Get cached performance reports and active sessions.",
1066
1246
  inputSchema: {
1067
- pageId: import_zod5.z.string().optional(),
1068
- recordingId: import_zod5.z.string().optional(),
1069
- limit: import_zod5.z.number().optional()
1247
+ pageId: import_zod6.z.string().optional(),
1248
+ recordingId: import_zod6.z.string().optional(),
1249
+ limit: import_zod6.z.number().optional()
1070
1250
  }
1071
1251
  },
1072
1252
  (input) => handleGetPerformanceReport(ctx, input)
@@ -1076,7 +1256,7 @@ function registerPerformanceTools(server, ctx) {
1076
1256
  {
1077
1257
  description: "Take a heap snapshot with CDP.",
1078
1258
  inputSchema: {
1079
- pageId: import_zod5.z.string().optional()
1259
+ pageId: import_zod6.z.string().optional()
1080
1260
  }
1081
1261
  },
1082
1262
  async (input) => handleTakeHeapSnapshot(ctx, input)
@@ -1333,7 +1513,7 @@ function toStructuredRecord(value) {
1333
1513
  }
1334
1514
 
1335
1515
  // src/mcp/tools/pages.ts
1336
- var import_zod6 = require("zod");
1516
+ var import_zod7 = require("zod");
1337
1517
 
1338
1518
  // src/plugin/entryDiscovery.ts
1339
1519
  var import_node_fs = __toESM(require("fs"), 1);
@@ -1358,10 +1538,10 @@ function walkHtmlEntries(root, dir, entries) {
1358
1538
  if (!item.isFile() || !item.name.endsWith(".html")) {
1359
1539
  continue;
1360
1540
  }
1361
- const relative2 = (0, import_vite.normalizePath)(import_node_path2.default.relative(root, fullPath));
1541
+ const relative3 = (0, import_vite.normalizePath)(import_node_path2.default.relative(root, fullPath));
1362
1542
  entries.push({
1363
- file: relative2,
1364
- pathname: relative2 === "index.html" ? "/" : `/${relative2}`
1543
+ file: relative3,
1544
+ pathname: relative3 === "index.html" ? "/" : `/${relative3}`
1365
1545
  });
1366
1546
  }
1367
1547
  }
@@ -1373,7 +1553,7 @@ function registerPageTools(server, ctx, vite) {
1373
1553
  {
1374
1554
  description: "List Vite page entries and connected runtime/CDP targets.",
1375
1555
  inputSchema: {
1376
- includeDisconnected: import_zod6.z.boolean().optional()
1556
+ includeDisconnected: import_zod7.z.boolean().optional()
1377
1557
  }
1378
1558
  },
1379
1559
  async (input) => {
@@ -1396,8 +1576,8 @@ function registerPageTools(server, ctx, vite) {
1396
1576
  {
1397
1577
  description: "Reload the selected page. CDP uses ignoreCache; Runtime Hook falls back to normal reload.",
1398
1578
  inputSchema: {
1399
- pageId: import_zod6.z.string().optional(),
1400
- ignoreCache: import_zod6.z.boolean().optional()
1579
+ pageId: import_zod7.z.string().optional(),
1580
+ ignoreCache: import_zod7.z.boolean().optional()
1401
1581
  }
1402
1582
  },
1403
1583
  async (input) => {
@@ -1548,8 +1728,430 @@ function getPathname(url) {
1548
1728
  }
1549
1729
  }
1550
1730
 
1731
+ // src/mcp/tools/storage.ts
1732
+ var import_zod8 = require("zod");
1733
+
1734
+ // src/cdp/cdpStorage.ts
1735
+ function createCdpStorageAdapter(client) {
1736
+ return {
1737
+ async manageStorage(request) {
1738
+ try {
1739
+ return await manageCdpStorage(client, request);
1740
+ } catch (error) {
1741
+ return createCdpStorageError(
1742
+ request,
1743
+ error instanceof Error ? error.message : String(error)
1744
+ );
1745
+ }
1746
+ }
1747
+ };
1748
+ }
1749
+ async function manageCdpStorage(client, request) {
1750
+ if (request.scope === "cookie") {
1751
+ return manageCdpCookies(client, request);
1752
+ }
1753
+ if (request.scope === "indexedDB") {
1754
+ return manageCdpIndexedDb(client, request);
1755
+ }
1756
+ return manageCdpDomStorage(client, request);
1757
+ }
1758
+ async function manageCdpCookies(client, request) {
1759
+ if (request.action === "list" || request.action === "get") {
1760
+ const result2 = await client.Storage.getCookies();
1761
+ const cookies2 = result2.cookies.filter(
1762
+ (cookie) => isCookieInOrigin(cookie, request.origin)
1763
+ );
1764
+ return createCdpStorageSuccess(request, {
1765
+ origin: request.origin,
1766
+ cookies: request.action === "get" && request.cookie?.name ? cookies2.filter((cookie) => cookie.name === request.cookie?.name) : cookies2
1767
+ });
1768
+ }
1769
+ if (request.action === "set") {
1770
+ if (!request.cookie?.name) {
1771
+ throw new Error("Cookie name is required for set operation");
1772
+ }
1773
+ await client.Storage.setCookies({
1774
+ cookies: [
1775
+ {
1776
+ name: request.cookie.name,
1777
+ value: request.cookie.value ?? request.value ?? "",
1778
+ url: request.cookie.url ?? request.origin,
1779
+ domain: request.cookie.domain,
1780
+ path: request.cookie.path,
1781
+ httpOnly: request.cookie.httpOnly,
1782
+ secure: request.cookie.secure,
1783
+ sameSite: normalizeCookieSameSite(request.cookie.sameSite),
1784
+ expires: request.cookie.expires
1785
+ }
1786
+ ]
1787
+ });
1788
+ return createCdpStorageSuccess(request, { ok: true });
1789
+ }
1790
+ const result = await client.Storage.getCookies();
1791
+ const cookies = result.cookies.filter(
1792
+ (cookie) => isCookieInOrigin(cookie, request.origin)
1793
+ );
1794
+ const candidates = request.action === "delete" && request.cookie?.name ? cookies.filter((cookie) => cookie.name === request.cookie?.name) : cookies;
1795
+ const deletable = candidates.filter((cookie) => !cookie.httpOnly);
1796
+ const skippedHttpOnlyCount = candidates.length - deletable.length;
1797
+ for (const cookie of deletable) {
1798
+ await client.Network.deleteCookies({
1799
+ name: cookie.name,
1800
+ domain: cookie.domain,
1801
+ path: cookie.path
1802
+ });
1803
+ }
1804
+ return createCdpStorageSuccess(request, {
1805
+ deletedCount: deletable.length,
1806
+ skippedHttpOnlyCount
1807
+ });
1808
+ }
1809
+ async function manageCdpDomStorage(client, request) {
1810
+ const storageId = {
1811
+ securityOrigin: request.origin,
1812
+ isLocalStorage: request.scope === "localStorage"
1813
+ };
1814
+ if (request.action === "list") {
1815
+ const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
1816
+ return createCdpStorageSuccess(request, {
1817
+ origin: request.origin,
1818
+ scope: request.scope,
1819
+ entries: result2.entries.map(([key, value]) => ({ key, value }))
1820
+ });
1821
+ }
1822
+ if (request.action === "get") {
1823
+ assertStorageKey(request);
1824
+ const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
1825
+ const entry = result2.entries.find(([key]) => key === request.key);
1826
+ return createCdpStorageSuccess(request, {
1827
+ key: request.key,
1828
+ value: entry?.[1] ?? null
1829
+ });
1830
+ }
1831
+ if (request.action === "set") {
1832
+ assertStorageKey(request);
1833
+ await client.DOMStorage.setDOMStorageItem({
1834
+ storageId,
1835
+ key: request.key,
1836
+ value: request.value ?? ""
1837
+ });
1838
+ return createCdpStorageSuccess(request, { ok: true });
1839
+ }
1840
+ if (request.action === "delete") {
1841
+ assertStorageKey(request);
1842
+ await client.DOMStorage.removeDOMStorageItem({
1843
+ storageId,
1844
+ key: request.key
1845
+ });
1846
+ return createCdpStorageSuccess(request, { ok: true });
1847
+ }
1848
+ const result = await client.DOMStorage.getDOMStorageItems({ storageId });
1849
+ for (const [key] of result.entries) {
1850
+ await client.DOMStorage.removeDOMStorageItem({ storageId, key });
1851
+ }
1852
+ return createCdpStorageSuccess(request, { deletedCount: result.entries.length });
1853
+ }
1854
+ async function manageCdpIndexedDb(client, request) {
1855
+ if (request.action === "list") {
1856
+ const result = await client.IndexedDB.requestDatabaseNames({
1857
+ securityOrigin: request.origin
1858
+ });
1859
+ return createCdpStorageSuccess(request, {
1860
+ origin: request.origin,
1861
+ databases: result.databaseNames
1862
+ });
1863
+ }
1864
+ assertIndexedDbTarget(request);
1865
+ if (request.action === "get") {
1866
+ const result = await client.IndexedDB.requestData({
1867
+ securityOrigin: request.origin,
1868
+ databaseName: request.databaseName,
1869
+ objectStoreName: request.objectStoreName,
1870
+ indexName: request.indexName ?? "",
1871
+ skipCount: 0,
1872
+ pageSize: 100
1873
+ });
1874
+ return createCdpStorageSuccess(request, {
1875
+ entries: result.objectStoreDataEntries,
1876
+ hasMore: result.hasMore
1877
+ });
1878
+ }
1879
+ if (request.action === "delete") {
1880
+ assertStorageKey(request);
1881
+ await client.IndexedDB.deleteObjectStoreEntries({
1882
+ securityOrigin: request.origin,
1883
+ databaseName: request.databaseName,
1884
+ objectStoreName: request.objectStoreName,
1885
+ keyRange: createExactCdpKeyRange(request.key)
1886
+ });
1887
+ return createCdpStorageSuccess(request, { ok: true });
1888
+ }
1889
+ if (request.action === "clear") {
1890
+ if (request.objectStoreName) {
1891
+ await client.IndexedDB.clearObjectStore({
1892
+ securityOrigin: request.origin,
1893
+ databaseName: request.databaseName,
1894
+ objectStoreName: request.objectStoreName
1895
+ });
1896
+ return createCdpStorageSuccess(request, { ok: true });
1897
+ }
1898
+ await client.IndexedDB.deleteDatabase({
1899
+ securityOrigin: request.origin,
1900
+ databaseName: request.databaseName
1901
+ });
1902
+ return createCdpStorageSuccess(request, { ok: true });
1903
+ }
1904
+ return createCdpStorageError(
1905
+ request,
1906
+ "IndexedDB set operation requires runtime bridge"
1907
+ );
1908
+ }
1909
+ function isCookieInOrigin(cookie, origin) {
1910
+ const hostname = new URL(origin).hostname;
1911
+ const domain = cookie.domain?.replace(/^\./, "");
1912
+ return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)));
1913
+ }
1914
+ function normalizeCookieSameSite(sameSite) {
1915
+ if (!sameSite) {
1916
+ return void 0;
1917
+ }
1918
+ if (sameSite === "strict") {
1919
+ return "Strict";
1920
+ }
1921
+ if (sameSite === "lax") {
1922
+ return "Lax";
1923
+ }
1924
+ return "None";
1925
+ }
1926
+ function createExactCdpKeyRange(key) {
1927
+ const parsedKey = parseJsonValue(key);
1928
+ return {
1929
+ lower: parsedKey,
1930
+ upper: parsedKey,
1931
+ lowerOpen: false,
1932
+ upperOpen: false
1933
+ };
1934
+ }
1935
+ function parseJsonValue(value) {
1936
+ try {
1937
+ return JSON.parse(value);
1938
+ } catch {
1939
+ return value;
1940
+ }
1941
+ }
1942
+ function assertStorageKey(request) {
1943
+ if (!request.key) {
1944
+ throw new Error("Storage key is required for this operation");
1945
+ }
1946
+ }
1947
+ function assertIndexedDbTarget(request) {
1948
+ if (!request.databaseName || !request.objectStoreName) {
1949
+ throw new Error("IndexedDB databaseName and objectStoreName are required");
1950
+ }
1951
+ }
1952
+ function createCdpStorageSuccess(request, data) {
1953
+ return {
1954
+ ok: true,
1955
+ source: "cdp",
1956
+ action: request.action,
1957
+ scope: request.scope,
1958
+ data
1959
+ };
1960
+ }
1961
+ function createCdpStorageError(request, error) {
1962
+ return {
1963
+ ok: false,
1964
+ source: "cdp",
1965
+ action: request.action,
1966
+ scope: request.scope,
1967
+ error
1968
+ };
1969
+ }
1970
+
1971
+ // src/mcp/tools/storage.ts
1972
+ function registerStorageTools(server, ctx) {
1973
+ registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {
1974
+ description: "List same-origin storage and CDP cookies when available.",
1975
+ inputSchema: {
1976
+ pageId: import_zod8.z.string().optional()
1977
+ },
1978
+ action: "list",
1979
+ handler: (input) => handleListStorage(ctx, input.pageId)
1980
+ });
1981
+ registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {
1982
+ description: "Read one storage entry.",
1983
+ inputSchema: createStorageInputSchema(),
1984
+ action: "get",
1985
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "get" })
1986
+ });
1987
+ registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {
1988
+ description: "Write one storage entry.",
1989
+ inputSchema: createStorageInputSchema(),
1990
+ action: "set",
1991
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "set" })
1992
+ });
1993
+ registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {
1994
+ description: "Delete one storage entry.",
1995
+ inputSchema: createStorageInputSchema(),
1996
+ action: "delete",
1997
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "delete" })
1998
+ });
1999
+ registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {
2000
+ description: "Clear one storage scope.",
2001
+ inputSchema: createStorageInputSchema(),
2002
+ action: "clear",
2003
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "clear" })
2004
+ });
2005
+ }
2006
+ function registerStorageTool(server, name, options) {
2007
+ server.registerTool(
2008
+ name,
2009
+ {
2010
+ description: options.description,
2011
+ inputSchema: options.inputSchema
2012
+ },
2013
+ (async (input) => options.handler(
2014
+ input
2015
+ ))
2016
+ );
2017
+ }
2018
+ function createStorageInputSchema() {
2019
+ return {
2020
+ pageId: import_zod8.z.string().optional(),
2021
+ scope: import_zod8.z.enum(["localStorage", "sessionStorage", "indexedDB", "cookie"]).optional(),
2022
+ key: import_zod8.z.string().optional(),
2023
+ value: import_zod8.z.string().optional(),
2024
+ databaseName: import_zod8.z.string().optional(),
2025
+ objectStoreName: import_zod8.z.string().optional(),
2026
+ indexName: import_zod8.z.string().optional(),
2027
+ cookie: import_zod8.z.object({
2028
+ name: import_zod8.z.string(),
2029
+ value: import_zod8.z.string().optional(),
2030
+ domain: import_zod8.z.string().optional(),
2031
+ path: import_zod8.z.string().optional(),
2032
+ url: import_zod8.z.string().optional(),
2033
+ httpOnly: import_zod8.z.boolean().optional(),
2034
+ secure: import_zod8.z.boolean().optional(),
2035
+ sameSite: import_zod8.z.enum(["strict", "lax", "none"]).optional(),
2036
+ expires: import_zod8.z.number().optional()
2037
+ }).optional()
2038
+ };
2039
+ }
2040
+ async function handleListStorage(ctx, pageId) {
2041
+ let baseRequest;
2042
+ try {
2043
+ baseRequest = createStorageRequest(ctx, {
2044
+ pageId,
2045
+ action: "list",
2046
+ scope: "localStorage"
2047
+ });
2048
+ } catch (error) {
2049
+ return createToolError(error instanceof Error ? error.message : String(error));
2050
+ }
2051
+ const [localStorage, sessionStorage, indexedDB] = await Promise.all([
2052
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "localStorage" }),
2053
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "sessionStorage" }),
2054
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "indexedDB" })
2055
+ ]);
2056
+ const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId);
2057
+ return createToolResponse({
2058
+ ok: true,
2059
+ origin: baseRequest.origin,
2060
+ localStorage: extractStorageData(localStorage),
2061
+ sessionStorage: extractStorageData(sessionStorage),
2062
+ indexedDB: extractStorageData(indexedDB),
2063
+ cookie
2064
+ });
2065
+ }
2066
+ async function handleStorageAction(ctx, input) {
2067
+ let request;
2068
+ try {
2069
+ request = createStorageRequest(ctx, input);
2070
+ } catch (error) {
2071
+ return createToolError(error instanceof Error ? error.message : String(error));
2072
+ }
2073
+ const cdp = await connectCdpForPage(ctx, input.pageId);
2074
+ if (cdp && shouldUseCdpStorage(request)) {
2075
+ try {
2076
+ const result2 = await createCdpStorageAdapter(cdp.client).manageStorage(
2077
+ request
2078
+ );
2079
+ return createToolResponse(result2);
2080
+ } finally {
2081
+ await closeCdpClient(cdp.client);
2082
+ }
2083
+ }
2084
+ const result = await requestRuntimeStorage(ctx, request);
2085
+ return createToolResponse(result);
2086
+ }
2087
+ async function requestRuntimeStorage(ctx, request) {
2088
+ return requestRuntimeData(ctx, (event) => {
2089
+ void ctx.rpcServer?.manageStorage({
2090
+ ...request,
2091
+ event
2092
+ });
2093
+ });
2094
+ }
2095
+ async function listCookiesIfCdpAvailable(ctx, request, pageId) {
2096
+ if (!hasCdpConfig2(ctx)) {
2097
+ return extractStorageData(
2098
+ await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
2099
+ );
2100
+ }
2101
+ const cdp = await connectCdpForPage(ctx, pageId);
2102
+ if (!cdp) {
2103
+ return extractStorageData(
2104
+ await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
2105
+ );
2106
+ }
2107
+ try {
2108
+ const result = await createCdpStorageAdapter(cdp.client).manageStorage({
2109
+ ...request,
2110
+ scope: "cookie"
2111
+ });
2112
+ return extractStorageData(result);
2113
+ } finally {
2114
+ await closeCdpClient(cdp.client);
2115
+ }
2116
+ }
2117
+ function extractStorageData(result) {
2118
+ if (!isStorageResultRecord(result)) {
2119
+ return result;
2120
+ }
2121
+ return result.data ?? result;
2122
+ }
2123
+ function isStorageResultRecord(value) {
2124
+ return typeof value === "object" && value !== null && "ok" in value;
2125
+ }
2126
+ function shouldUseCdpStorage(request) {
2127
+ return request.scope === "cookie";
2128
+ }
2129
+ function createStorageRequest(ctx, input) {
2130
+ const page = resolvePageTarget(ctx, input.pageId);
2131
+ const origin = new URL(page.url).origin;
2132
+ return {
2133
+ event: "",
2134
+ pageId: page.pageId,
2135
+ origin,
2136
+ action: input.action,
2137
+ scope: normalizeScope(input.scope),
2138
+ key: input.key,
2139
+ value: input.value,
2140
+ databaseName: input.databaseName,
2141
+ objectStoreName: input.objectStoreName,
2142
+ indexName: input.indexName,
2143
+ cookie: input.cookie
2144
+ };
2145
+ }
2146
+ function normalizeScope(scope) {
2147
+ return scope ?? "localStorage";
2148
+ }
2149
+ function hasCdpConfig2(ctx) {
2150
+ return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint);
2151
+ }
2152
+
1551
2153
  // src/mcp/tools/screenshot.ts
1552
- var import_zod7 = require("zod");
2154
+ var import_zod9 = require("zod");
1553
2155
 
1554
2156
  // src/cdp/cdpScreenshot.ts
1555
2157
  async function cdpCaptureScreenshot(options) {
@@ -1709,14 +2311,14 @@ function createProjectRelativePath(ctx, filePath) {
1709
2311
  var DEFAULT_SCREENSHOT_TARGET = "viewport";
1710
2312
  var DEFAULT_SCREENSHOT_FORMAT = "png";
1711
2313
  var screenshotInputSchema = {
1712
- pageId: import_zod7.z.string().optional(),
1713
- target: import_zod7.z.enum(["viewport", "fullPage", "element"]).optional(),
1714
- selector: import_zod7.z.string().optional(),
1715
- format: import_zod7.z.enum(["png", "jpeg", "webp"]).optional(),
1716
- prefer: import_zod7.z.enum(["auto", "cdp", "runtime"]).optional(),
1717
- quality: import_zod7.z.number().optional(),
1718
- scale: import_zod7.z.number().optional(),
1719
- snapdom: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).optional()
2314
+ pageId: import_zod9.z.string().optional(),
2315
+ target: import_zod9.z.enum(["viewport", "fullPage", "element"]).optional(),
2316
+ selector: import_zod9.z.string().optional(),
2317
+ format: import_zod9.z.enum(["png", "jpeg", "webp"]).optional(),
2318
+ prefer: import_zod9.z.enum(["auto", "cdp", "runtime"]).optional(),
2319
+ quality: import_zod9.z.number().optional(),
2320
+ scale: import_zod9.z.number().optional(),
2321
+ snapdom: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.unknown()).optional()
1720
2322
  };
1721
2323
  function registerScreenshotTools(server, ctx) {
1722
2324
  server.registerTool(
@@ -1836,7 +2438,7 @@ function isScreenshotImagePayload(result) {
1836
2438
 
1837
2439
  // src/mcp/tools/vue.ts
1838
2440
  var import_nanoid3 = require("nanoid");
1839
- var import_zod8 = require("zod");
2441
+ var import_zod10 = require("zod");
1840
2442
  function registerVueTools(server, ctx) {
1841
2443
  server.registerTool(
1842
2444
  MCP_TOOL_NAMES.getComponentTree,
@@ -1849,7 +2451,7 @@ function registerVueTools(server, ctx) {
1849
2451
  MCP_TOOL_NAMES.getComponentState,
1850
2452
  {
1851
2453
  description: "Get Vue component state.",
1852
- inputSchema: { componentName: import_zod8.z.string() }
2454
+ inputSchema: { componentName: import_zod10.z.string() }
1853
2455
  },
1854
2456
  async ({ componentName }) => requestVueData(ctx, (event) => {
1855
2457
  void ctx.rpcServer?.getInspectorState({ event, componentName });
@@ -1860,10 +2462,10 @@ function registerVueTools(server, ctx) {
1860
2462
  {
1861
2463
  description: "Edit Vue component state.",
1862
2464
  inputSchema: {
1863
- componentName: import_zod8.z.string(),
1864
- path: import_zod8.z.array(import_zod8.z.string()),
1865
- value: import_zod8.z.string(),
1866
- valueType: import_zod8.z.enum(["string", "number", "boolean", "object", "array"])
2465
+ componentName: import_zod10.z.string(),
2466
+ path: import_zod10.z.array(import_zod10.z.string()),
2467
+ value: import_zod10.z.string(),
2468
+ valueType: import_zod10.z.enum(["string", "number", "boolean", "object", "array"])
1867
2469
  }
1868
2470
  },
1869
2471
  ({ componentName, path: path8, value, valueType }) => {
@@ -1883,7 +2485,7 @@ function registerVueTools(server, ctx) {
1883
2485
  MCP_TOOL_NAMES.highlightComponent,
1884
2486
  {
1885
2487
  description: "Highlight a Vue component.",
1886
- inputSchema: { componentName: import_zod8.z.string() }
2488
+ inputSchema: { componentName: import_zod10.z.string() }
1887
2489
  },
1888
2490
  ({ componentName }) => {
1889
2491
  if (!ctx.rpcServer) {
@@ -1911,7 +2513,7 @@ function registerVueTools(server, ctx) {
1911
2513
  MCP_TOOL_NAMES.getPiniaState,
1912
2514
  {
1913
2515
  description: "Get Pinia store state.",
1914
- inputSchema: { storeName: import_zod8.z.string() }
2516
+ inputSchema: { storeName: import_zod10.z.string() }
1915
2517
  },
1916
2518
  async ({ storeName }) => requestVueData(ctx, (event) => {
1917
2519
  void ctx.rpcServer?.getPiniaState({ event, storeName });
@@ -1954,10 +2556,12 @@ function createMcpServer(ctx, vite) {
1954
2556
  });
1955
2557
  registerPageTools(server, ctx, vite);
1956
2558
  registerDomTools(server, ctx);
2559
+ registerElementContextTools(server, ctx);
1957
2560
  registerScreenshotTools(server, ctx);
1958
2561
  registerConsoleTools(server, ctx);
1959
2562
  registerEvaluateTools(server, ctx);
1960
2563
  registerNetworkTools(server, ctx);
2564
+ registerStorageTools(server, ctx);
1961
2565
  registerPerformanceTools(server, ctx);
1962
2566
  registerVueTools(server, ctx);
1963
2567
  return server;
@@ -2034,6 +2638,10 @@ function createServerVueRuntimeRpc(ctx) {
2034
2638
  onDomQueryUpdated: (event, data) => {
2035
2639
  void ctx.hooks.callHook(event, data);
2036
2640
  },
2641
+ getElementContext: () => void 0,
2642
+ onElementContextUpdated: (event, data) => {
2643
+ void ctx.hooks.callHook(event, data);
2644
+ },
2037
2645
  reloadPage: () => void 0,
2038
2646
  onPageReloaded: (event, data) => {
2039
2647
  void ctx.hooks.callHook(event, data);
@@ -2046,6 +2654,10 @@ function createServerVueRuntimeRpc(ctx) {
2046
2654
  onScreenshotTaken: (event, data) => {
2047
2655
  void ctx.hooks.callHook(event, data);
2048
2656
  },
2657
+ manageStorage: () => void 0,
2658
+ onStorageUpdated: (event, data) => {
2659
+ void ctx.hooks.callHook(event, data);
2660
+ },
2049
2661
  recordPerformance: () => void 0,
2050
2662
  onPerformanceRecorded: (event, data) => {
2051
2663
  void ctx.hooks.callHook(event, data);
@@ -2342,9 +2954,85 @@ async function startCdpObservers(ctx, target, client) {
2342
2954
  }
2343
2955
  }
2344
2956
 
2957
+ // src/plugin/elementInstrumentation.ts
2958
+ var import_compiler_sfc = require("@vue/compiler-sfc");
2959
+ var import_magic_string = __toESM(require("magic-string"), 1);
2960
+ var import_node_path4 = require("path");
2961
+ var VUE_FILE_SUFFIX = ".vue";
2962
+ var ELEMENT_NODE_TYPE = 1;
2963
+ var SKIPPED_TAGS = /* @__PURE__ */ new Set(["template", "slot", "script", "style"]);
2964
+ var MCP_ID_ATTR = "data-v-mcp-id";
2965
+ function createElementInstrumentationController(options) {
2966
+ return {
2967
+ transform(code, id, ssr) {
2968
+ if (ssr || shouldSkipInstrumentation(id)) {
2969
+ return void 0;
2970
+ }
2971
+ const filename = id.split("?", 1)[0];
2972
+ if (!filename.endsWith(VUE_FILE_SUFFIX)) {
2973
+ return void 0;
2974
+ }
2975
+ const parsed = (0, import_compiler_sfc.parse)(code, { filename });
2976
+ const template = parsed.descriptor.template;
2977
+ if (!template?.ast) {
2978
+ return void 0;
2979
+ }
2980
+ const s = new import_magic_string.default(code);
2981
+ const relativeFile = normalizePath2((0, import_node_path4.relative)(options.root, filename));
2982
+ for (const node of template.ast.children) {
2983
+ injectNodeId(s, node, relativeFile);
2984
+ }
2985
+ if (!s.hasChanged()) {
2986
+ return void 0;
2987
+ }
2988
+ return {
2989
+ code: s.toString(),
2990
+ map: s.generateMap({ hires: true })
2991
+ };
2992
+ }
2993
+ };
2994
+ }
2995
+ function shouldSkipInstrumentation(id) {
2996
+ if (id.startsWith("\0")) {
2997
+ return true;
2998
+ }
2999
+ const normalized = normalizePath2(id);
3000
+ if (normalized.includes("/node_modules/")) {
3001
+ return true;
3002
+ }
3003
+ return !normalized.startsWith("/") && !/^[A-Za-z]:\//.test(normalized);
3004
+ }
3005
+ function normalizePath2(path8) {
3006
+ return path8.replace(/\\/g, "/");
3007
+ }
3008
+ function injectNodeId(s, node, relativeFile) {
3009
+ if (node.type !== ELEMENT_NODE_TYPE || !node.tag || !node.loc) {
3010
+ return;
3011
+ }
3012
+ if (!SKIPPED_TAGS.has(node.tag) && !hasMcpIdAttr(node)) {
3013
+ const id = `${relativeFile}:${String(node.loc.start.line)}:${String(node.loc.start.column)}`;
3014
+ const insertAt = node.loc.start.offset + node.tag.length + 1;
3015
+ s.appendLeft(insertAt, ` ${MCP_ID_ATTR}="${id}"`);
3016
+ }
3017
+ for (const child of node.children ?? []) {
3018
+ injectNodeId(s, child, relativeFile);
3019
+ }
3020
+ }
3021
+ function hasMcpIdAttr(node) {
3022
+ return (node.props ?? []).some((prop) => {
3023
+ if (!isTemplateProp(prop)) {
3024
+ return false;
3025
+ }
3026
+ return prop.name === MCP_ID_ATTR;
3027
+ });
3028
+ }
3029
+ function isTemplateProp(value) {
3030
+ return Boolean(value && typeof value === "object" && "name" in value);
3031
+ }
3032
+
2345
3033
  // src/plugin/injectRuntime.ts
2346
3034
  var import_node_module = require("module");
2347
- var import_node_path4 = require("path");
3035
+ var import_node_path5 = require("path");
2348
3036
  function createRuntimeInjectionController(options, getConfig) {
2349
3037
  return {
2350
3038
  resolveId(importee) {
@@ -2361,7 +3049,7 @@ function createRuntimeInjectionController(options, getConfig) {
2361
3049
  },
2362
3050
  load(id) {
2363
3051
  if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {
2364
- return createRuntimeModule();
3052
+ return createRuntimeModule(options, getConfig()?.root);
2365
3053
  }
2366
3054
  if (id === RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID) {
2367
3055
  return createScreenshotConfigModule(options);
@@ -2404,14 +3092,17 @@ ${code}`;
2404
3092
  }
2405
3093
  };
2406
3094
  }
2407
- function createRuntimeModule() {
3095
+ function createRuntimeModule(options, root) {
2408
3096
  return [
2409
3097
  "import { setScreenshotModuleRegistry, setSnapdomLoader, startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';",
2410
3098
  `import { screenshotModuleRegistry } from '${VIRTUAL_SCREENSHOT_CONFIG_ID}';`,
2411
3099
  `import { loadSnapdom } from '${VIRTUAL_SNAPDOM_LOADER_ID}';`,
2412
3100
  "setScreenshotModuleRegistry(screenshotModuleRegistry);",
2413
3101
  "setSnapdomLoader(loadSnapdom);",
2414
- "void startRuntimeClient();"
3102
+ `void startRuntimeClient(${JSON.stringify({
3103
+ elementPicker: options.elementPicker,
3104
+ projectRoot: root
3105
+ })});`
2415
3106
  ].join("\n");
2416
3107
  }
2417
3108
  function createSnapdomLoaderModule(root) {
@@ -2428,7 +3119,7 @@ function createSnapdomLoaderModule(root) {
2428
3119
  }
2429
3120
  function canResolveSnapdomFromProject(root) {
2430
3121
  try {
2431
- (0, import_node_module.createRequire)((0, import_node_path4.join)(root ?? process.cwd(), "package.json")).resolve(
3122
+ (0, import_node_module.createRequire)((0, import_node_path5.join)(root ?? process.cwd(), "package.json")).resolve(
2432
3123
  "@zumer/snapdom"
2433
3124
  );
2434
3125
  return true;
@@ -2468,16 +3159,16 @@ function getPluginPath(plugin) {
2468
3159
 
2469
3160
  // src/plugin/mcpClientConfig/index.ts
2470
3161
  var import_promises5 = __toESM(require("fs/promises"), 1);
2471
- var import_node_path7 = __toESM(require("path"), 1);
3162
+ var import_node_path8 = __toESM(require("path"), 1);
2472
3163
 
2473
3164
  // src/plugin/mcpClientConfig/codexConfig.ts
2474
3165
  var import_promises3 = __toESM(require("fs/promises"), 1);
2475
- var import_node_path5 = __toESM(require("path"), 1);
3166
+ var import_node_path6 = __toESM(require("path"), 1);
2476
3167
  async function updateCodexMcpClientConfig(options) {
2477
3168
  try {
2478
3169
  const current = await readOptionalTextFile(options.configPath);
2479
3170
  const next = replaceOrAppendOwnedBlock(current, options);
2480
- await import_promises3.default.mkdir(import_node_path5.default.dirname(options.configPath), { recursive: true });
3171
+ await import_promises3.default.mkdir(import_node_path6.default.dirname(options.configPath), { recursive: true });
2481
3172
  await import_promises3.default.writeFile(options.configPath, next);
2482
3173
  } catch (error) {
2483
3174
  console.warn(
@@ -2577,7 +3268,7 @@ function isNodeError(error) {
2577
3268
 
2578
3269
  // src/plugin/mcpClientConfig/jsonConfig.ts
2579
3270
  var import_promises4 = __toESM(require("fs/promises"), 1);
2580
- var import_node_path6 = __toESM(require("path"), 1);
3271
+ var import_node_path7 = __toESM(require("path"), 1);
2581
3272
  async function updateJsonMcpClientConfig(options) {
2582
3273
  try {
2583
3274
  const config = await readJsonConfig(options.configPath);
@@ -2617,7 +3308,7 @@ function renameLegacyServer(mcpServers, options) {
2617
3308
  );
2618
3309
  }
2619
3310
  async function writeJsonConfig(configPath, config) {
2620
- await import_promises4.default.mkdir(import_node_path6.default.dirname(configPath), { recursive: true });
3311
+ await import_promises4.default.mkdir(import_node_path7.default.dirname(configPath), { recursive: true });
2621
3312
  await import_promises4.default.writeFile(configPath, `${JSON.stringify(config, null, 2)}
2622
3313
  `);
2623
3314
  }
@@ -2662,12 +3353,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
2662
3353
  root,
2663
3354
  clientName: "cursor",
2664
3355
  enabled: options.cursor,
2665
- entryPath: import_node_path7.default.join(root, ".cursor"),
3356
+ entryPath: import_node_path8.default.join(root, ".cursor"),
2666
3357
  entryKind: "directory",
2667
3358
  userOptions,
2668
3359
  createJob: () => updateJsonMcpClientConfig({
2669
3360
  clientName: "Cursor",
2670
- configPath: import_node_path7.default.join(root, ".cursor", "mcp.json"),
3361
+ configPath: import_node_path8.default.join(root, ".cursor", "mcp.json"),
2671
3362
  mcpUrl: sseUrl,
2672
3363
  serverName,
2673
3364
  legacyServerNames
@@ -2677,11 +3368,11 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
2677
3368
  root,
2678
3369
  clientName: "codex",
2679
3370
  enabled: options.codex,
2680
- entryPath: import_node_path7.default.join(root, ".codex"),
3371
+ entryPath: import_node_path8.default.join(root, ".codex"),
2681
3372
  entryKind: "directory",
2682
3373
  userOptions,
2683
3374
  createJob: () => updateCodexMcpClientConfig({
2684
- configPath: import_node_path7.default.join(root, ".codex", "config.toml"),
3375
+ configPath: import_node_path8.default.join(root, ".codex", "config.toml"),
2685
3376
  mcpUrl: streamableHttpUrl,
2686
3377
  serverName,
2687
3378
  legacyServerNames
@@ -2691,12 +3382,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
2691
3382
  root,
2692
3383
  clientName: "claudeCode",
2693
3384
  enabled: options.claudeCode,
2694
- entryPath: import_node_path7.default.join(root, ".mcp.json"),
3385
+ entryPath: import_node_path8.default.join(root, ".mcp.json"),
2695
3386
  entryKind: "file",
2696
3387
  userOptions,
2697
3388
  createJob: () => updateJsonMcpClientConfig({
2698
3389
  clientName: "Claude Code",
2699
- configPath: import_node_path7.default.join(root, ".mcp.json"),
3390
+ configPath: import_node_path8.default.join(root, ".mcp.json"),
2700
3391
  mcpUrl: sseUrl,
2701
3392
  serverName,
2702
3393
  legacyServerNames
@@ -2706,12 +3397,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
2706
3397
  root,
2707
3398
  clientName: "trae",
2708
3399
  enabled: options.trae,
2709
- entryPath: import_node_path7.default.join(root, ".trae"),
3400
+ entryPath: import_node_path8.default.join(root, ".trae"),
2710
3401
  entryKind: "directory",
2711
3402
  userOptions,
2712
3403
  createJob: () => updateJsonMcpClientConfig({
2713
3404
  clientName: "Trae",
2714
- configPath: import_node_path7.default.join(root, ".trae", "mcp.json"),
3405
+ configPath: import_node_path8.default.join(root, ".trae", "mcp.json"),
2715
3406
  mcpUrl: sseUrl,
2716
3407
  serverName,
2717
3408
  legacyServerNames
@@ -2771,11 +3462,11 @@ function isNodeError3(error) {
2771
3462
 
2772
3463
  // src/plugin/skillConfig/index.ts
2773
3464
  var import_promises7 = __toESM(require("fs/promises"), 1);
2774
- var import_node_path9 = __toESM(require("path"), 1);
3465
+ var import_node_path10 = __toESM(require("path"), 1);
2775
3466
 
2776
3467
  // src/plugin/skillConfig/writers.ts
2777
3468
  var import_promises6 = __toESM(require("fs/promises"), 1);
2778
- var import_node_path8 = __toESM(require("path"), 1);
3469
+ var import_node_path9 = __toESM(require("path"), 1);
2779
3470
  var GENERATED_SKILL_CONFIG_MARKER = "<!-- Generated by vite-plugin-vue-mcp-next. Safe to edit, but automatic updates only apply while this marker remains. -->";
2780
3471
  async function writeGeneratedTextFile(options) {
2781
3472
  try {
@@ -2786,7 +3477,7 @@ async function writeGeneratedTextFile(options) {
2786
3477
  );
2787
3478
  return;
2788
3479
  }
2789
- await import_promises6.default.mkdir(import_node_path8.default.dirname(options.filePath), { recursive: true });
3480
+ await import_promises6.default.mkdir(import_node_path9.default.dirname(options.filePath), { recursive: true });
2790
3481
  await import_promises6.default.writeFile(options.filePath, options.content);
2791
3482
  } catch (error) {
2792
3483
  console.warn(
@@ -2813,7 +3504,7 @@ function isNodeError4(error) {
2813
3504
 
2814
3505
  // src/plugin/skillConfig/index.ts
2815
3506
  var PACKAGE_NAME = "@xiaou66/vite-plugin-vue-mcp-next";
2816
- var PACKAGED_SKILL_PATH = import_node_path9.default.join("skills", "vite-mcp-next", "SKILL.md");
3507
+ var PACKAGED_SKILL_PATH = import_node_path10.default.join("skills", "vite-mcp-next", "SKILL.md");
2817
3508
  async function updateSkillConfigs(root, options) {
2818
3509
  if (!options.autoConfig) {
2819
3510
  return;
@@ -2829,13 +3520,13 @@ async function updateSkillConfigs(root, options) {
2829
3520
  function createSkillConfigDescriptors(root) {
2830
3521
  return [
2831
3522
  {
2832
- entryPath: import_node_path9.default.join(root, ".codex"),
2833
- filePath: import_node_path9.default.join(root, ".codex", "skills", "vite-mcp-next", "SKILL.md"),
3523
+ entryPath: import_node_path10.default.join(root, ".codex"),
3524
+ filePath: import_node_path10.default.join(root, ".codex", "skills", "vite-mcp-next", "SKILL.md"),
2834
3525
  targetName: "Codex skill"
2835
3526
  },
2836
3527
  {
2837
- entryPath: import_node_path9.default.join(root, ".claude"),
2838
- filePath: import_node_path9.default.join(
3528
+ entryPath: import_node_path10.default.join(root, ".claude"),
3529
+ filePath: import_node_path10.default.join(
2839
3530
  root,
2840
3531
  ".claude",
2841
3532
  "skills",
@@ -2845,8 +3536,8 @@ function createSkillConfigDescriptors(root) {
2845
3536
  targetName: "Claude Code skill"
2846
3537
  },
2847
3538
  {
2848
- entryPath: import_node_path9.default.join(root, ".cursor"),
2849
- filePath: import_node_path9.default.join(root, ".cursor", "rules", "vite-mcp-next.mdc"),
3539
+ entryPath: import_node_path10.default.join(root, ".cursor"),
3540
+ filePath: import_node_path10.default.join(root, ".cursor", "rules", "vite-mcp-next.mdc"),
2850
3541
  targetName: "Cursor rule"
2851
3542
  }
2852
3543
  ];
@@ -2894,9 +3585,9 @@ async function safelyReadPackagedSkillContent(root) {
2894
3585
  }
2895
3586
  function getPackagedSkillCandidates(root) {
2896
3587
  return [
2897
- import_node_path9.default.resolve(root, "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
2898
- import_node_path9.default.resolve(process.cwd(), "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
2899
- import_node_path9.default.resolve(process.cwd(), PACKAGED_SKILL_PATH)
3588
+ import_node_path10.default.resolve(root, "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
3589
+ import_node_path10.default.resolve(process.cwd(), "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
3590
+ import_node_path10.default.resolve(process.cwd(), PACKAGED_SKILL_PATH)
2900
3591
  ];
2901
3592
  }
2902
3593
  async function hasDirectoryEntry(entryPath) {
@@ -2930,6 +3621,7 @@ function vueMcpNext(userOptions = {}) {
2930
3621
  options,
2931
3622
  () => config
2932
3623
  );
3624
+ let elementInstrumentation;
2933
3625
  const cdpLifecycle = createCdpLifecycleController(ctx);
2934
3626
  ctx.cdpLifecycle = cdpLifecycle;
2935
3627
  return {
@@ -2938,6 +3630,9 @@ function vueMcpNext(userOptions = {}) {
2938
3630
  apply: "serve",
2939
3631
  configResolved(resolvedConfig) {
2940
3632
  config = resolvedConfig;
3633
+ elementInstrumentation = createElementInstrumentationController({
3634
+ root: resolvedConfig.root
3635
+ });
2941
3636
  },
2942
3637
  async configureServer(server) {
2943
3638
  ctx.server = server;
@@ -3041,7 +3736,21 @@ function vueMcpNext(userOptions = {}) {
3041
3736
  return runtimeInjection.load(id);
3042
3737
  },
3043
3738
  transform(code, id, transformOptions) {
3044
- return runtimeInjection.transform(code, id, transformOptions?.ssr);
3739
+ const instrumented = elementInstrumentation?.transform(
3740
+ code,
3741
+ id,
3742
+ transformOptions?.ssr
3743
+ );
3744
+ const nextCode = instrumented && typeof instrumented === "object" && "code" in instrumented && typeof instrumented.code === "string" ? instrumented.code : code;
3745
+ const runtimeInjected = runtimeInjection.transform(
3746
+ nextCode,
3747
+ id,
3748
+ transformOptions?.ssr
3749
+ );
3750
+ if (runtimeInjected) {
3751
+ return runtimeInjected;
3752
+ }
3753
+ return instrumented;
3045
3754
  },
3046
3755
  transformIndexHtml(html) {
3047
3756
  return runtimeInjection.transformIndexHtml(html);