@xiaou66/vite-plugin-vue-mcp-next 0.0.1

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 ADDED
@@ -0,0 +1,1519 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => vueMcpNext,
34
+ vueMcpNext: () => vueMcpNext
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/plugin/createPlugin.ts
39
+ var import_vite2 = require("vite");
40
+
41
+ // src/shared/limits.ts
42
+ var DEFAULT_DOM_MAX_DEPTH = 8;
43
+ var DEFAULT_DOM_MAX_NODES = 2e3;
44
+ var DEFAULT_DOM_MAX_TEXT_LENGTH = 300;
45
+ var DEFAULT_CONSOLE_MAX_RECORDS = 1e3;
46
+ var DEFAULT_NETWORK_MAX_RECORDS = 500;
47
+ var DEFAULT_NETWORK_MAX_BODY_SIZE = 1e5;
48
+ var DEFAULT_MASK_HEADERS = [
49
+ "authorization",
50
+ "cookie",
51
+ "set-cookie"
52
+ ];
53
+
54
+ // src/constants.ts
55
+ var DEFAULT_MCP_PATH = "/__mcp";
56
+ var MCP_TOOL_NAMES = {
57
+ listPages: "list_pages",
58
+ getPageState: "get_page_state",
59
+ getDomTree: "get_dom_tree",
60
+ queryDom: "query_dom",
61
+ getConsoleLogs: "get_console_logs",
62
+ clearConsoleLogs: "clear_console_logs",
63
+ evaluateScript: "evaluate_script",
64
+ getNetworkRequests: "get_network_requests",
65
+ getNetworkRequestDetail: "get_network_request_detail",
66
+ clearNetworkRequests: "clear_network_requests",
67
+ getComponentTree: "get_component_tree",
68
+ getComponentState: "get_component_state",
69
+ editComponentState: "edit_component_state",
70
+ highlightComponent: "highlight_component",
71
+ getRouterInfo: "get_router_info",
72
+ getPiniaTree: "get_pinia_tree",
73
+ getPiniaState: "get_pinia_state"
74
+ };
75
+ var VIRTUAL_RUNTIME_ID = "virtual:vite-plugin-vue-mcp-next/runtime";
76
+ var RESOLVED_VIRTUAL_RUNTIME_ID = `\0${VIRTUAL_RUNTIME_ID}`;
77
+ var DEFAULT_MCP_CLIENT_SERVER_NAME = "vue-mcp-next";
78
+ var DEFAULT_OPTIONS = {
79
+ mcpPath: DEFAULT_MCP_PATH,
80
+ host: "localhost",
81
+ printUrl: true,
82
+ updateCursorMcpJson: {
83
+ enabled: true,
84
+ serverName: DEFAULT_MCP_CLIENT_SERVER_NAME
85
+ },
86
+ mcpClients: {
87
+ cursor: true,
88
+ codex: true,
89
+ claudeCode: true,
90
+ trae: true,
91
+ serverName: DEFAULT_MCP_CLIENT_SERVER_NAME
92
+ },
93
+ runtime: {
94
+ mode: "auto",
95
+ evaluate: {
96
+ enabled: false,
97
+ timeoutMs: 3e3
98
+ }
99
+ },
100
+ cdp: {},
101
+ network: {
102
+ mode: "auto",
103
+ maxRecords: DEFAULT_NETWORK_MAX_RECORDS,
104
+ captureRequestBody: true,
105
+ captureResponseBody: true,
106
+ maxBodySize: DEFAULT_NETWORK_MAX_BODY_SIZE,
107
+ maskHeaders: [...DEFAULT_MASK_HEADERS]
108
+ },
109
+ dom: {
110
+ maxDepth: DEFAULT_DOM_MAX_DEPTH,
111
+ maxNodes: DEFAULT_DOM_MAX_NODES,
112
+ maxTextLength: DEFAULT_DOM_MAX_TEXT_LENGTH
113
+ },
114
+ console: {
115
+ maxRecords: DEFAULT_CONSOLE_MAX_RECORDS
116
+ }
117
+ };
118
+ function mergeMcpClientOptions(cursorConfig, mcpClients) {
119
+ return {
120
+ ...DEFAULT_OPTIONS.mcpClients,
121
+ cursor: cursorConfig.enabled,
122
+ serverName: cursorConfig.serverName,
123
+ ...mcpClients
124
+ };
125
+ }
126
+ function mergeOptions(options = {}) {
127
+ const cursorConfig = typeof options.updateCursorMcpJson === "boolean" ? {
128
+ enabled: options.updateCursorMcpJson,
129
+ serverName: DEFAULT_OPTIONS.updateCursorMcpJson.serverName
130
+ } : {
131
+ ...DEFAULT_OPTIONS.updateCursorMcpJson,
132
+ ...options.updateCursorMcpJson
133
+ };
134
+ const mcpClients = mergeMcpClientOptions(cursorConfig, options.mcpClients);
135
+ return {
136
+ ...DEFAULT_OPTIONS,
137
+ ...options,
138
+ updateCursorMcpJson: cursorConfig,
139
+ mcpClients,
140
+ runtime: {
141
+ ...DEFAULT_OPTIONS.runtime,
142
+ ...options.runtime,
143
+ evaluate: {
144
+ ...DEFAULT_OPTIONS.runtime.evaluate,
145
+ ...options.runtime?.evaluate
146
+ }
147
+ },
148
+ cdp: {
149
+ ...DEFAULT_OPTIONS.cdp,
150
+ ...options.cdp
151
+ },
152
+ network: {
153
+ ...DEFAULT_OPTIONS.network,
154
+ ...options.network,
155
+ maskHeaders: options.network?.maskHeaders ?? [
156
+ ...DEFAULT_OPTIONS.network.maskHeaders
157
+ ]
158
+ },
159
+ dom: {
160
+ ...DEFAULT_OPTIONS.dom,
161
+ ...options.dom
162
+ },
163
+ console: {
164
+ ...DEFAULT_OPTIONS.console,
165
+ ...options.console
166
+ }
167
+ };
168
+ }
169
+
170
+ // src/context.ts
171
+ var import_hookable = require("hookable");
172
+
173
+ // src/shared/ringBuffer.ts
174
+ function createRingBuffer(capacity) {
175
+ const items = [];
176
+ return {
177
+ push(value) {
178
+ items.push(value);
179
+ while (items.length > capacity) {
180
+ items.shift();
181
+ }
182
+ },
183
+ all() {
184
+ return [...items];
185
+ },
186
+ clear() {
187
+ items.length = 0;
188
+ }
189
+ };
190
+ }
191
+
192
+ // src/context.ts
193
+ function createPageTargetRegistry() {
194
+ const targets = /* @__PURE__ */ new Map();
195
+ return {
196
+ upsert(target) {
197
+ targets.set(target.pageId, target);
198
+ },
199
+ get(pageId) {
200
+ return targets.get(pageId);
201
+ },
202
+ list() {
203
+ return [...targets.values()];
204
+ },
205
+ disconnect(pageId) {
206
+ const target = targets.get(pageId);
207
+ if (!target) {
208
+ return;
209
+ }
210
+ targets.set(pageId, { ...target, connected: false });
211
+ }
212
+ };
213
+ }
214
+ function createVueMcpNextContext(options) {
215
+ return {
216
+ options,
217
+ hooks: (0, import_hookable.createHooks)(),
218
+ rpcServer: void 0,
219
+ pages: createPageTargetRegistry(),
220
+ consoleRecords: createRingBuffer(options.console.maxRecords),
221
+ networkRecords: createRingBuffer(options.network.maxRecords)
222
+ };
223
+ }
224
+
225
+ // src/mcp/createMcpServer.ts
226
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
227
+
228
+ // src/mcp/tools/console.ts
229
+ var import_zod = require("zod");
230
+
231
+ // src/mcp/routeTools.ts
232
+ var import_nanoid = require("nanoid");
233
+
234
+ // src/cdp/cdpClient.ts
235
+ var import_chrome_remote_interface = __toESM(require("chrome-remote-interface"), 1);
236
+ function createCdpClient(options) {
237
+ return {
238
+ async listTargets() {
239
+ if (!options.browserUrl) {
240
+ return [];
241
+ }
242
+ const listUrl = new URL("/json/list", options.browserUrl);
243
+ const response = await fetch(listUrl);
244
+ return await response.json();
245
+ },
246
+ async connect(wsEndpoint) {
247
+ return (0, import_chrome_remote_interface.default)({ target: wsEndpoint });
248
+ }
249
+ };
250
+ }
251
+
252
+ // src/cdp/targetMatcher.ts
253
+ function matchCdpTarget(targets, options) {
254
+ const pageTargets = targets.filter(
255
+ (target) => target.type === "page" && target.webSocketDebuggerUrl
256
+ );
257
+ if (options.url) {
258
+ const exact = pageTargets.find((target) => target.url === options.url);
259
+ if (exact) {
260
+ return exact;
261
+ }
262
+ }
263
+ if (options.targetUrlPattern) {
264
+ const pattern = options.targetUrlPattern;
265
+ return pageTargets.find(
266
+ (target) => typeof pattern === "string" ? target.url.includes(pattern) : pattern.test(target.url)
267
+ );
268
+ }
269
+ return pageTargets[0];
270
+ }
271
+
272
+ // src/mcp/routeTools.ts
273
+ function shouldUseCdp(options) {
274
+ if (options.capabilityMode === "off" || options.capabilityMode === "hook") {
275
+ return false;
276
+ }
277
+ if (!options.hasMatchedCdpTarget) {
278
+ return false;
279
+ }
280
+ return Boolean(
281
+ options.options.cdp.browserUrl || options.options.cdp.wsEndpoint
282
+ );
283
+ }
284
+ function createToolResponse(data) {
285
+ return {
286
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
287
+ structuredContent: data
288
+ };
289
+ }
290
+ function createToolError(message, data) {
291
+ return createToolResponse({
292
+ ok: false,
293
+ error: message,
294
+ data
295
+ });
296
+ }
297
+ function resolvePageTarget(ctx, pageId) {
298
+ const targets = ctx.pages.list().filter((target) => target.connected);
299
+ if (pageId) {
300
+ const target = targets.find((item) => item.pageId === pageId);
301
+ if (!target) {
302
+ throw new Error(`Page target not found: ${pageId}`);
303
+ }
304
+ return target;
305
+ }
306
+ if (targets.length === 1) {
307
+ return targets[0];
308
+ }
309
+ throw new Error(
310
+ "Multiple or no page targets available. Call list_pages and pass pageId."
311
+ );
312
+ }
313
+ async function connectCdpForPage(ctx, pageId) {
314
+ if (!ctx.options.cdp.browserUrl && !ctx.options.cdp.wsEndpoint) {
315
+ return void 0;
316
+ }
317
+ const cdp = createCdpClient(ctx.options.cdp);
318
+ if (ctx.options.cdp.wsEndpoint) {
319
+ return { client: await cdp.connect(ctx.options.cdp.wsEndpoint) };
320
+ }
321
+ const page = resolvePageTarget(ctx, pageId);
322
+ const target = matchCdpTarget(await cdp.listTargets(), {
323
+ url: page.url,
324
+ targetUrlPattern: ctx.options.cdp.targetUrlPattern
325
+ });
326
+ if (!target?.webSocketDebuggerUrl) {
327
+ return void 0;
328
+ }
329
+ return { client: await cdp.connect(target.webSocketDebuggerUrl), target };
330
+ }
331
+ async function closeCdpClient(client) {
332
+ await client.close();
333
+ }
334
+ async function requestRuntimeData(ctx, trigger) {
335
+ if (!ctx.rpcServer) {
336
+ return { ok: false, error: "runtime bridge is not connected" };
337
+ }
338
+ const event = (0, import_nanoid.nanoid)();
339
+ return new Promise((resolve) => {
340
+ const timeout = setTimeout(() => {
341
+ resolve({ ok: false, error: "runtime bridge response timed out" });
342
+ }, 5e3);
343
+ ctx.hooks.hookOnce(event, (data) => {
344
+ clearTimeout(timeout);
345
+ resolve(data);
346
+ });
347
+ trigger(event);
348
+ });
349
+ }
350
+
351
+ // src/mcp/tools/console.ts
352
+ function registerConsoleTools(server, ctx) {
353
+ server.registerTool(
354
+ MCP_TOOL_NAMES.getConsoleLogs,
355
+ {
356
+ description: "Get console logs for the selected page.",
357
+ inputSchema: {
358
+ pageId: import_zod.z.string().optional(),
359
+ level: import_zod.z.enum(["log", "info", "warn", "error", "debug"]).optional(),
360
+ limit: import_zod.z.number().optional()
361
+ }
362
+ },
363
+ (input) => {
364
+ const logs = ctx.consoleRecords.all().filter((record) => !input.pageId || record.pageId === input.pageId).filter((record) => !input.level || record.level === input.level).slice(-(input.limit ?? ctx.options.console.maxRecords));
365
+ return createToolResponse({ logs });
366
+ }
367
+ );
368
+ server.registerTool(
369
+ MCP_TOOL_NAMES.clearConsoleLogs,
370
+ {
371
+ description: "Clear cached console logs for the selected page.",
372
+ inputSchema: {
373
+ pageId: import_zod.z.string().optional()
374
+ }
375
+ },
376
+ () => {
377
+ ctx.consoleRecords.clear();
378
+ return createToolResponse({ ok: true });
379
+ }
380
+ );
381
+ }
382
+
383
+ // src/mcp/tools/dom.ts
384
+ var import_zod2 = require("zod");
385
+
386
+ // src/cdp/cdpDom.ts
387
+ async function cdpGetDomSnapshot(client) {
388
+ await client.DOMSnapshot.enable();
389
+ return client.DOMSnapshot.captureSnapshot({
390
+ computedStyles: []
391
+ });
392
+ }
393
+ async function cdpQueryDom(client, selector, limit) {
394
+ 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() }))`;
395
+ const result = await client.Runtime.evaluate({
396
+ expression,
397
+ returnByValue: true
398
+ });
399
+ if (result.exceptionDetails) {
400
+ throw new Error(result.exceptionDetails.text || "CDP query DOM failed");
401
+ }
402
+ return result.result.value;
403
+ }
404
+
405
+ // src/mcp/tools/dom.ts
406
+ function registerDomTools(server, ctx) {
407
+ server.registerTool(
408
+ MCP_TOOL_NAMES.getDomTree,
409
+ {
410
+ description: "Get a clipped DOM tree for the selected page.",
411
+ inputSchema: {
412
+ pageId: import_zod2.z.string().optional(),
413
+ maxDepth: import_zod2.z.number().optional(),
414
+ maxNodes: import_zod2.z.number().optional()
415
+ }
416
+ },
417
+ async (input) => {
418
+ const cdp = await connectCdpForPage(ctx, input.pageId);
419
+ if (cdp && shouldUseCdp({
420
+ options: ctx.options,
421
+ capabilityMode: ctx.options.runtime.mode,
422
+ hasMatchedCdpTarget: true
423
+ })) {
424
+ try {
425
+ const snapshot2 = await cdpGetDomSnapshot(cdp.client);
426
+ return createToolResponse({
427
+ source: "cdp",
428
+ snapshot: snapshot2,
429
+ limits: {
430
+ maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,
431
+ maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes
432
+ }
433
+ });
434
+ } finally {
435
+ await closeCdpClient(cdp.client);
436
+ }
437
+ }
438
+ const snapshot = await requestRuntimeData(ctx, (event) => {
439
+ void ctx.rpcServer?.getDomTree({
440
+ event,
441
+ maxDepth: input.maxDepth ?? ctx.options.dom.maxDepth,
442
+ maxNodes: input.maxNodes ?? ctx.options.dom.maxNodes,
443
+ maxTextLength: ctx.options.dom.maxTextLength
444
+ });
445
+ });
446
+ return createToolResponse({ source: "hook", snapshot });
447
+ }
448
+ );
449
+ server.registerTool(
450
+ MCP_TOOL_NAMES.queryDom,
451
+ {
452
+ description: "Query DOM nodes by selector in the selected page.",
453
+ inputSchema: {
454
+ pageId: import_zod2.z.string().optional(),
455
+ selector: import_zod2.z.string(),
456
+ limit: import_zod2.z.number().optional()
457
+ }
458
+ },
459
+ async (input) => {
460
+ const cdp = await connectCdpForPage(ctx, input.pageId);
461
+ if (cdp && shouldUseCdp({
462
+ options: ctx.options,
463
+ capabilityMode: ctx.options.runtime.mode,
464
+ hasMatchedCdpTarget: true
465
+ })) {
466
+ try {
467
+ const nodes2 = await cdpQueryDom(
468
+ cdp.client,
469
+ input.selector,
470
+ input.limit ?? 20
471
+ );
472
+ return createToolResponse({ source: "cdp", nodes: nodes2 });
473
+ } finally {
474
+ await closeCdpClient(cdp.client);
475
+ }
476
+ }
477
+ const nodes = await requestRuntimeData(ctx, (event) => {
478
+ void ctx.rpcServer?.queryDom({
479
+ event,
480
+ selector: input.selector,
481
+ limit: input.limit ?? 20
482
+ });
483
+ });
484
+ return createToolResponse({ source: "hook", nodes });
485
+ }
486
+ );
487
+ }
488
+
489
+ // src/mcp/tools/evaluate.ts
490
+ var import_zod3 = require("zod");
491
+
492
+ // src/cdp/cdpEvaluate.ts
493
+ async function cdpEvaluate(options) {
494
+ const result = await options.client.Runtime.evaluate({
495
+ expression: options.expression,
496
+ awaitPromise: options.awaitPromise ?? true,
497
+ returnByValue: true
498
+ });
499
+ if (result.exceptionDetails) {
500
+ throw new Error(result.exceptionDetails.text || "CDP evaluate failed");
501
+ }
502
+ return result.result.value;
503
+ }
504
+
505
+ // src/mcp/tools/evaluate.ts
506
+ function registerEvaluateTools(server, ctx) {
507
+ server.registerTool(
508
+ MCP_TOOL_NAMES.evaluateScript,
509
+ {
510
+ description: "Evaluate a script in the selected page when explicitly enabled.",
511
+ inputSchema: {
512
+ pageId: import_zod3.z.string().optional(),
513
+ expression: import_zod3.z.string(),
514
+ awaitPromise: import_zod3.z.boolean().optional()
515
+ }
516
+ },
517
+ async (input) => {
518
+ try {
519
+ assertEvaluateEnabled(ctx.options);
520
+ } catch (error) {
521
+ return createToolError(
522
+ error instanceof Error ? error.message : String(error)
523
+ );
524
+ }
525
+ const cdp = await connectCdpForPage(ctx, input.pageId);
526
+ if (cdp && shouldUseCdp({
527
+ options: ctx.options,
528
+ capabilityMode: ctx.options.runtime.mode,
529
+ hasMatchedCdpTarget: true
530
+ })) {
531
+ try {
532
+ const value = await cdpEvaluate({
533
+ client: cdp.client,
534
+ expression: input.expression,
535
+ awaitPromise: input.awaitPromise
536
+ });
537
+ return createToolResponse({ source: "cdp", value });
538
+ } finally {
539
+ await closeCdpClient(cdp.client);
540
+ }
541
+ }
542
+ const result = await requestRuntimeData(ctx, (event) => {
543
+ void ctx.rpcServer?.evaluateScript({
544
+ event,
545
+ expression: input.expression,
546
+ awaitPromise: input.awaitPromise,
547
+ timeoutMs: ctx.options.runtime.evaluate.timeoutMs
548
+ });
549
+ });
550
+ return createToolResponse({ source: "hook", result });
551
+ }
552
+ );
553
+ }
554
+ function assertEvaluateEnabled(options) {
555
+ if (!options.runtime.evaluate.enabled) {
556
+ throw new Error(
557
+ "evaluate_script is disabled. Enable runtime.evaluate.enabled to use it."
558
+ );
559
+ }
560
+ }
561
+
562
+ // src/mcp/tools/network.ts
563
+ var import_zod4 = require("zod");
564
+ function registerNetworkTools(server, ctx) {
565
+ server.registerTool(
566
+ MCP_TOOL_NAMES.getNetworkRequests,
567
+ {
568
+ description: "Get captured network request summaries.",
569
+ inputSchema: {
570
+ pageId: import_zod4.z.string().optional(),
571
+ urlContains: import_zod4.z.string().optional(),
572
+ method: import_zod4.z.string().optional(),
573
+ status: import_zod4.z.number().optional(),
574
+ limit: import_zod4.z.number().optional()
575
+ }
576
+ },
577
+ (input) => {
578
+ if (ctx.options.network.mode === "off") {
579
+ return createToolError(
580
+ "Network collection is disabled by configuration"
581
+ );
582
+ }
583
+ const records = ctx.networkRecords.all().filter((record) => !input.pageId || record.pageId === input.pageId).filter(
584
+ (record) => !input.urlContains || record.url.includes(input.urlContains)
585
+ ).filter(
586
+ (record) => !input.method || record.method.toUpperCase() === input.method.toUpperCase()
587
+ ).filter(
588
+ (record) => input.status === void 0 || record.status === input.status
589
+ ).slice(-(input.limit ?? ctx.options.network.maxRecords));
590
+ return createToolResponse({ requests: records });
591
+ }
592
+ );
593
+ server.registerTool(
594
+ MCP_TOOL_NAMES.getNetworkRequestDetail,
595
+ {
596
+ description: "Get captured network request detail by id.",
597
+ inputSchema: { id: import_zod4.z.string() }
598
+ },
599
+ (input) => {
600
+ if (ctx.options.network.mode === "off") {
601
+ return createToolError(
602
+ "Network collection is disabled by configuration"
603
+ );
604
+ }
605
+ const record = ctx.networkRecords.all().find((item) => item.id === input.id);
606
+ return createToolResponse({ request: record ?? null });
607
+ }
608
+ );
609
+ server.registerTool(
610
+ MCP_TOOL_NAMES.clearNetworkRequests,
611
+ {
612
+ description: "Clear cached network requests.",
613
+ inputSchema: {
614
+ pageId: import_zod4.z.string().optional()
615
+ }
616
+ },
617
+ () => {
618
+ ctx.networkRecords.clear();
619
+ return createToolResponse({ ok: true });
620
+ }
621
+ );
622
+ }
623
+
624
+ // src/plugin/entryDiscovery.ts
625
+ var import_node_fs = __toESM(require("fs"), 1);
626
+ var import_node_path = __toESM(require("path"), 1);
627
+ var import_vite = require("vite");
628
+ function discoverHtmlEntries(server) {
629
+ const root = server.config.root;
630
+ const entries = [];
631
+ walkHtmlEntries(root, root, entries);
632
+ return entries;
633
+ }
634
+ function walkHtmlEntries(root, dir, entries) {
635
+ for (const item of import_node_fs.default.readdirSync(dir, { withFileTypes: true })) {
636
+ if (item.name === "node_modules" || item.name.startsWith(".")) {
637
+ continue;
638
+ }
639
+ const fullPath = import_node_path.default.join(dir, item.name);
640
+ if (item.isDirectory()) {
641
+ walkHtmlEntries(root, fullPath, entries);
642
+ continue;
643
+ }
644
+ if (!item.isFile() || !item.name.endsWith(".html")) {
645
+ continue;
646
+ }
647
+ const relative = (0, import_vite.normalizePath)(import_node_path.default.relative(root, fullPath));
648
+ entries.push({
649
+ file: relative,
650
+ pathname: relative === "index.html" ? "/" : `/${relative}`
651
+ });
652
+ }
653
+ }
654
+
655
+ // src/mcp/tools/pages.ts
656
+ function registerPageTools(server, ctx, vite) {
657
+ server.registerTool(
658
+ MCP_TOOL_NAMES.listPages,
659
+ {
660
+ description: "List Vite page entries and connected runtime/CDP targets."
661
+ },
662
+ async () => {
663
+ const cdpResult = await listCdpPageTargets(ctx);
664
+ for (const target of cdpResult.pages) {
665
+ ctx.pages.upsert(target);
666
+ void ctx.cdpLifecycle?.connectPage(target);
667
+ }
668
+ return createToolResponse({
669
+ entries: discoverHtmlEntries(vite),
670
+ pages: ctx.pages.list(),
671
+ cdpError: cdpResult.error
672
+ });
673
+ }
674
+ );
675
+ }
676
+ async function listCdpPageTargets(ctx) {
677
+ if (ctx.options.cdp.wsEndpoint) {
678
+ return { pages: [createWsEndpointTarget(ctx.options.cdp.wsEndpoint)] };
679
+ }
680
+ if (!ctx.options.cdp.browserUrl) {
681
+ return { pages: [] };
682
+ }
683
+ try {
684
+ const targets = await createCdpClient(ctx.options.cdp).listTargets();
685
+ return {
686
+ pages: targets.filter((target) => target.type === "page").map((target) => ({
687
+ pageId: `cdp:${target.id}`,
688
+ source: "cdp",
689
+ url: target.url,
690
+ pathname: getPathname(target.url),
691
+ title: target.title,
692
+ connected: Boolean(target.webSocketDebuggerUrl)
693
+ }))
694
+ };
695
+ } catch (error) {
696
+ return {
697
+ pages: [],
698
+ error: error instanceof Error ? error.message : String(error)
699
+ };
700
+ }
701
+ }
702
+ function createWsEndpointTarget(wsEndpoint) {
703
+ return {
704
+ pageId: "cdp:ws-endpoint",
705
+ source: "cdp",
706
+ url: wsEndpoint,
707
+ pathname: "cdp:ws-endpoint",
708
+ title: "CDP WebSocket endpoint",
709
+ connected: true
710
+ };
711
+ }
712
+ function getPathname(url) {
713
+ try {
714
+ return new URL(url).pathname;
715
+ } catch {
716
+ return url;
717
+ }
718
+ }
719
+
720
+ // src/mcp/tools/vue.ts
721
+ var import_nanoid2 = require("nanoid");
722
+ var import_zod5 = require("zod");
723
+ function registerVueTools(server, ctx) {
724
+ server.registerTool(
725
+ MCP_TOOL_NAMES.getComponentTree,
726
+ { description: "Get Vue component tree." },
727
+ async () => requestVueData(ctx, (event) => {
728
+ void ctx.rpcServer?.getInspectorTree({ event });
729
+ })
730
+ );
731
+ server.registerTool(
732
+ MCP_TOOL_NAMES.getComponentState,
733
+ {
734
+ description: "Get Vue component state.",
735
+ inputSchema: { componentName: import_zod5.z.string() }
736
+ },
737
+ async ({ componentName }) => requestVueData(ctx, (event) => {
738
+ void ctx.rpcServer?.getInspectorState({ event, componentName });
739
+ })
740
+ );
741
+ server.registerTool(
742
+ MCP_TOOL_NAMES.editComponentState,
743
+ {
744
+ description: "Edit Vue component state.",
745
+ inputSchema: {
746
+ componentName: import_zod5.z.string(),
747
+ path: import_zod5.z.array(import_zod5.z.string()),
748
+ value: import_zod5.z.string(),
749
+ valueType: import_zod5.z.enum(["string", "number", "boolean", "object", "array"])
750
+ }
751
+ },
752
+ ({ componentName, path: path5, value, valueType }) => {
753
+ if (!ctx.rpcServer) {
754
+ return vueBridgeUnavailable();
755
+ }
756
+ void ctx.rpcServer.editComponentState({
757
+ componentName,
758
+ path: path5,
759
+ value,
760
+ valueType
761
+ });
762
+ return createToolResponse({ ok: true });
763
+ }
764
+ );
765
+ server.registerTool(
766
+ MCP_TOOL_NAMES.highlightComponent,
767
+ {
768
+ description: "Highlight a Vue component.",
769
+ inputSchema: { componentName: import_zod5.z.string() }
770
+ },
771
+ ({ componentName }) => {
772
+ if (!ctx.rpcServer) {
773
+ return vueBridgeUnavailable();
774
+ }
775
+ void ctx.rpcServer.highlightComponent({ componentName });
776
+ return createToolResponse({ ok: true });
777
+ }
778
+ );
779
+ server.registerTool(
780
+ MCP_TOOL_NAMES.getRouterInfo,
781
+ { description: "Get Vue Router information." },
782
+ async () => requestVueData(ctx, (event) => {
783
+ ctx.rpcServer?.getRouterInfo({ event });
784
+ })
785
+ );
786
+ server.registerTool(
787
+ MCP_TOOL_NAMES.getPiniaTree,
788
+ { description: "Get Pinia inspector tree." },
789
+ async () => requestVueData(ctx, (event) => {
790
+ void ctx.rpcServer?.getPiniaTree({ event });
791
+ })
792
+ );
793
+ server.registerTool(
794
+ MCP_TOOL_NAMES.getPiniaState,
795
+ {
796
+ description: "Get Pinia store state.",
797
+ inputSchema: { storeName: import_zod5.z.string() }
798
+ },
799
+ async ({ storeName }) => requestVueData(ctx, (event) => {
800
+ void ctx.rpcServer?.getPiniaState({ event, storeName });
801
+ })
802
+ );
803
+ }
804
+ async function requestVueData(ctx, trigger) {
805
+ if (!ctx.rpcServer) {
806
+ return vueBridgeUnavailable();
807
+ }
808
+ const event = (0, import_nanoid2.nanoid)();
809
+ const data = await waitForVueHook(ctx, event, () => {
810
+ trigger(event);
811
+ });
812
+ return {
813
+ ...createToolResponse({ data })
814
+ };
815
+ }
816
+ function waitForVueHook(ctx, event, trigger) {
817
+ return new Promise((resolve) => {
818
+ const timeout = setTimeout(() => {
819
+ resolve({ ok: false, error: "Vue runtime bridge response timed out" });
820
+ }, 5e3);
821
+ ctx.hooks.hookOnce(event, (data) => {
822
+ clearTimeout(timeout);
823
+ resolve(data);
824
+ });
825
+ trigger();
826
+ });
827
+ }
828
+ function vueBridgeUnavailable() {
829
+ return createToolError("Vue runtime bridge is not connected");
830
+ }
831
+
832
+ // src/mcp/createMcpServer.ts
833
+ function createMcpServer(ctx, vite) {
834
+ const server = new import_mcp.McpServer({
835
+ name: "vite-plugin-vue-mcp-next",
836
+ version: "0.0.0"
837
+ });
838
+ registerPageTools(server, ctx, vite);
839
+ registerDomTools(server, ctx);
840
+ registerConsoleTools(server, ctx);
841
+ registerEvaluateTools(server, ctx);
842
+ registerNetworkTools(server, ctx);
843
+ registerVueTools(server, ctx);
844
+ return server;
845
+ }
846
+
847
+ // src/mcp/transport.ts
848
+ var import_sse = require("@modelcontextprotocol/sdk/server/sse.js");
849
+ function setupMcpTransport(base, server, vite) {
850
+ const transports = /* @__PURE__ */ new Map();
851
+ vite.middlewares.use(`${base}/sse`, (_req, res) => {
852
+ const transport = new import_sse.SSEServerTransport(`${base}/messages`, res);
853
+ transports.set(transport.sessionId, transport);
854
+ res.on("close", () => {
855
+ transports.delete(transport.sessionId);
856
+ });
857
+ void server.connect(transport).catch((error) => {
858
+ res.destroy(error instanceof Error ? error : new Error(String(error)));
859
+ });
860
+ });
861
+ vite.middlewares.use(`${base}/messages`, (req, res) => {
862
+ if (req.method !== "POST") {
863
+ res.statusCode = 405;
864
+ res.end("Method Not Allowed");
865
+ return;
866
+ }
867
+ const query = new URLSearchParams(req.url?.split("?").pop() || "");
868
+ const sessionId = query.get("sessionId");
869
+ if (!sessionId) {
870
+ res.statusCode = 400;
871
+ res.end("Bad Request");
872
+ return;
873
+ }
874
+ const transport = transports.get(sessionId);
875
+ if (!transport) {
876
+ res.statusCode = 404;
877
+ res.end("Not Found");
878
+ return;
879
+ }
880
+ void transport.handlePostMessage(req, res).catch((error) => {
881
+ res.destroy(error instanceof Error ? error : new Error(String(error)));
882
+ });
883
+ });
884
+ }
885
+
886
+ // src/mcp/vueRpc.ts
887
+ function createServerVueRuntimeRpc(ctx) {
888
+ return {
889
+ getDomTree: () => void 0,
890
+ onDomTreeUpdated: (event, data) => {
891
+ void ctx.hooks.callHook(event, data);
892
+ },
893
+ queryDom: () => void 0,
894
+ onDomQueryUpdated: (event, data) => {
895
+ void ctx.hooks.callHook(event, data);
896
+ },
897
+ evaluateScript: () => void 0,
898
+ onEvaluateScriptUpdated: (event, data) => {
899
+ void ctx.hooks.callHook(event, data);
900
+ },
901
+ getInspectorTree: () => void 0,
902
+ onInspectorTreeUpdated: (event, data) => {
903
+ void ctx.hooks.callHook(event, data);
904
+ },
905
+ getInspectorState: () => void 0,
906
+ onInspectorStateUpdated: (event, data) => {
907
+ void ctx.hooks.callHook(event, data);
908
+ },
909
+ editComponentState: () => void 0,
910
+ highlightComponent: () => void 0,
911
+ getRouterInfo: () => void 0,
912
+ onRouterInfoUpdated: (event, data) => {
913
+ void ctx.hooks.callHook(event, data);
914
+ },
915
+ getPiniaTree: () => void 0,
916
+ onPiniaTreeUpdated: (event, data) => {
917
+ void ctx.hooks.callHook(event, data);
918
+ },
919
+ getPiniaState: () => void 0,
920
+ onPiniaInfoUpdated: (event, data) => {
921
+ void ctx.hooks.callHook(event, data);
922
+ }
923
+ };
924
+ }
925
+
926
+ // src/cdp/cdpConsole.ts
927
+ var import_nanoid3 = require("nanoid");
928
+
929
+ // src/shared/serialization.ts
930
+ function safeStringify(value) {
931
+ if (typeof value === "string") {
932
+ return value;
933
+ }
934
+ const seen = /* @__PURE__ */ new WeakSet();
935
+ const serialized = JSON.stringify(
936
+ value,
937
+ (_key, current) => {
938
+ if (typeof current !== "object" || current === null) {
939
+ return current;
940
+ }
941
+ if (seen.has(current)) {
942
+ return "[Circular]";
943
+ }
944
+ seen.add(current);
945
+ return current;
946
+ }
947
+ );
948
+ return serialized;
949
+ }
950
+
951
+ // src/cdp/cdpConsole.ts
952
+ async function startCdpConsole(options) {
953
+ await options.client.Runtime.enable();
954
+ options.client.Runtime.consoleAPICalled((event) => {
955
+ options.push({
956
+ id: (0, import_nanoid3.nanoid)(),
957
+ pageId: options.pageId,
958
+ source: "cdp",
959
+ level: normalizeConsoleLevel(event.type),
960
+ message: event.args.map((arg) => safeStringify(arg.value ?? arg.description)).join(" "),
961
+ timestamp: event.timestamp
962
+ });
963
+ });
964
+ }
965
+ function normalizeConsoleLevel(level) {
966
+ if (level === "warning") {
967
+ return "warn";
968
+ }
969
+ if (level === "error" || level === "debug" || level === "info") {
970
+ return level;
971
+ }
972
+ return "log";
973
+ }
974
+
975
+ // src/cdp/cdpNetwork.ts
976
+ var import_nanoid4 = require("nanoid");
977
+
978
+ // src/shared/sanitize.ts
979
+ function maskHeaders(headers = {}, maskNames = []) {
980
+ const normalizedMaskNames = new Set(
981
+ maskNames.map((name) => name.toLowerCase())
982
+ );
983
+ return Object.fromEntries(
984
+ Object.entries(headers).map(([name, value]) => [
985
+ name,
986
+ normalizedMaskNames.has(name.toLowerCase()) ? "[masked]" : value
987
+ ])
988
+ );
989
+ }
990
+
991
+ // src/shared/url.ts
992
+ function parseRequestQuery(url) {
993
+ const parsed = new URL(url, "http://vite-plugin-vue-mcp-next.local");
994
+ const queryEntries = /* @__PURE__ */ new Map();
995
+ for (const [key, value] of parsed.searchParams.entries()) {
996
+ const existing = queryEntries.get(key);
997
+ if (existing === void 0) {
998
+ queryEntries.set(key, value);
999
+ continue;
1000
+ }
1001
+ if (Array.isArray(existing)) {
1002
+ existing.push(value);
1003
+ continue;
1004
+ }
1005
+ queryEntries.set(key, [existing, value]);
1006
+ }
1007
+ return Object.fromEntries(queryEntries);
1008
+ }
1009
+
1010
+ // src/cdp/cdpNetwork.ts
1011
+ async function startCdpNetwork(options) {
1012
+ const records = /* @__PURE__ */ new Map();
1013
+ await options.client.Network.enable();
1014
+ options.client.Network.requestWillBeSent((event) => {
1015
+ records.set(event.requestId, {
1016
+ id: (0, import_nanoid4.nanoid)(),
1017
+ pageId: options.pageId,
1018
+ source: "cdp",
1019
+ url: event.request.url,
1020
+ method: event.request.method,
1021
+ requestHeaders: maskHeaders(
1022
+ normalizeHeaders(event.request.headers),
1023
+ options.maskHeaders
1024
+ ),
1025
+ requestQuery: parseRequestQuery(event.request.url),
1026
+ requestBody: event.request.postData,
1027
+ startedAt: event.timestamp * 1e3
1028
+ });
1029
+ });
1030
+ options.client.Network.responseReceived((event) => {
1031
+ const record = records.get(event.requestId);
1032
+ if (!record) {
1033
+ return;
1034
+ }
1035
+ records.set(event.requestId, {
1036
+ ...record,
1037
+ status: event.response.status,
1038
+ responseHeaders: normalizeHeaders(event.response.headers)
1039
+ });
1040
+ });
1041
+ options.client.Network.loadingFinished((event) => {
1042
+ void finalizeCdpNetworkRecord(
1043
+ options,
1044
+ records,
1045
+ event.requestId,
1046
+ event.timestamp * 1e3
1047
+ );
1048
+ });
1049
+ options.client.Network.loadingFailed((event) => {
1050
+ const record = records.get(event.requestId);
1051
+ if (!record) {
1052
+ return;
1053
+ }
1054
+ records.delete(event.requestId);
1055
+ options.push({
1056
+ ...record,
1057
+ error: event.errorText,
1058
+ endedAt: event.timestamp * 1e3,
1059
+ durationMs: event.timestamp * 1e3 - record.startedAt
1060
+ });
1061
+ });
1062
+ }
1063
+ async function finalizeCdpNetworkRecord(options, records, requestId, endedAt) {
1064
+ const record = records.get(requestId);
1065
+ if (!record) {
1066
+ return;
1067
+ }
1068
+ records.delete(requestId);
1069
+ options.push({
1070
+ ...record,
1071
+ responseBody: options.captureResponseBody ? await safeGetResponseBody(options.client, requestId) : void 0,
1072
+ endedAt,
1073
+ durationMs: endedAt - record.startedAt
1074
+ });
1075
+ }
1076
+ async function safeGetResponseBody(client, requestId) {
1077
+ try {
1078
+ return (await client.Network.getResponseBody({ requestId })).body;
1079
+ } catch {
1080
+ return void 0;
1081
+ }
1082
+ }
1083
+ function normalizeHeaders(headers) {
1084
+ return Object.fromEntries(
1085
+ Object.entries(headers).map(([key, value]) => [key, String(value)])
1086
+ );
1087
+ }
1088
+
1089
+ // src/plugin/cdpLifecycle.ts
1090
+ function createCdpLifecycleController(ctx) {
1091
+ const clients = /* @__PURE__ */ new Map();
1092
+ return {
1093
+ async connectPage(target) {
1094
+ if (clients.has(target.pageId) || !shouldStartCdp(ctx)) {
1095
+ return;
1096
+ }
1097
+ const client = await safeConnectCdp(ctx, target);
1098
+ if (!client) {
1099
+ return;
1100
+ }
1101
+ clients.set(target.pageId, client);
1102
+ try {
1103
+ await startCdpObservers(ctx, target, client);
1104
+ } catch (error) {
1105
+ clients.delete(target.pageId);
1106
+ await client.close();
1107
+ warnWhenCdpForced(ctx, error);
1108
+ }
1109
+ },
1110
+ async closeAll() {
1111
+ await Promise.all([...clients.values()].map((client) => client.close()));
1112
+ clients.clear();
1113
+ }
1114
+ };
1115
+ }
1116
+ function shouldStartCdp(ctx) {
1117
+ const consoleUsesCdp = shouldUseCdp({
1118
+ options: ctx.options,
1119
+ capabilityMode: ctx.options.runtime.mode,
1120
+ hasMatchedCdpTarget: true
1121
+ });
1122
+ const networkUsesCdp = shouldUseCdp({
1123
+ options: ctx.options,
1124
+ capabilityMode: ctx.options.network.mode,
1125
+ hasMatchedCdpTarget: true
1126
+ });
1127
+ return consoleUsesCdp || networkUsesCdp;
1128
+ }
1129
+ async function safeConnectCdp(ctx, target) {
1130
+ try {
1131
+ return await connectCdp(ctx, target);
1132
+ } catch (error) {
1133
+ warnWhenCdpForced(ctx, error);
1134
+ return void 0;
1135
+ }
1136
+ }
1137
+ function warnWhenCdpForced(ctx, error) {
1138
+ if (ctx.options.runtime.mode !== "cdp" && ctx.options.network.mode !== "cdp") {
1139
+ return;
1140
+ }
1141
+ console.warn(
1142
+ `[vite-plugin-vue-mcp-next] CDP connect failed: ${error instanceof Error ? error.message : String(error)}`
1143
+ );
1144
+ }
1145
+ async function connectCdp(ctx, target) {
1146
+ const cdp = createCdpClient(ctx.options.cdp);
1147
+ if (ctx.options.cdp.wsEndpoint) {
1148
+ return cdp.connect(ctx.options.cdp.wsEndpoint);
1149
+ }
1150
+ if (!ctx.options.cdp.browserUrl) {
1151
+ return void 0;
1152
+ }
1153
+ const matched = matchCdpTarget(await cdp.listTargets(), {
1154
+ url: target.url,
1155
+ targetUrlPattern: ctx.options.cdp.targetUrlPattern
1156
+ });
1157
+ if (!matched?.webSocketDebuggerUrl) {
1158
+ return void 0;
1159
+ }
1160
+ return cdp.connect(matched.webSocketDebuggerUrl);
1161
+ }
1162
+ async function startCdpObservers(ctx, target, client) {
1163
+ if (ctx.options.runtime.mode !== "hook") {
1164
+ await startCdpConsole({
1165
+ client,
1166
+ pageId: target.pageId,
1167
+ push: (record) => {
1168
+ ctx.consoleRecords.push(record);
1169
+ }
1170
+ });
1171
+ }
1172
+ if (ctx.options.network.mode === "auto" || ctx.options.network.mode === "cdp") {
1173
+ await startCdpNetwork({
1174
+ client,
1175
+ pageId: target.pageId,
1176
+ maskHeaders: ctx.options.network.maskHeaders,
1177
+ captureResponseBody: ctx.options.network.captureResponseBody,
1178
+ push: (record) => {
1179
+ ctx.networkRecords.push(record);
1180
+ }
1181
+ });
1182
+ }
1183
+ }
1184
+
1185
+ // src/plugin/injectRuntime.ts
1186
+ function createRuntimeInjectionController(options, getConfig) {
1187
+ return {
1188
+ resolveId(importee) {
1189
+ if (importee === VIRTUAL_RUNTIME_ID) {
1190
+ return RESOLVED_VIRTUAL_RUNTIME_ID;
1191
+ }
1192
+ return void 0;
1193
+ },
1194
+ load(id) {
1195
+ if (id !== RESOLVED_VIRTUAL_RUNTIME_ID) {
1196
+ return void 0;
1197
+ }
1198
+ return "import { startRuntimeClient } from 'vite-plugin-vue-mcp-next/runtime/client';\nvoid startRuntimeClient();";
1199
+ },
1200
+ transformIndexHtml(html) {
1201
+ if (options.appendTo) {
1202
+ return void 0;
1203
+ }
1204
+ const base = getConfig()?.base || "/";
1205
+ return {
1206
+ html,
1207
+ tags: [
1208
+ {
1209
+ tag: "script",
1210
+ injectTo: "head-prepend",
1211
+ attrs: {
1212
+ type: "module",
1213
+ src: `${base}@id/${VIRTUAL_RUNTIME_ID}`
1214
+ }
1215
+ }
1216
+ ]
1217
+ };
1218
+ },
1219
+ transform(code, id, ssr) {
1220
+ if (ssr || !options.appendTo) {
1221
+ return void 0;
1222
+ }
1223
+ const [filename] = id.split("?", 2);
1224
+ const matched = typeof options.appendTo === "string" ? filename.endsWith(options.appendTo) : options.appendTo.test(filename);
1225
+ if (!matched) {
1226
+ return void 0;
1227
+ }
1228
+ return `import '${VIRTUAL_RUNTIME_ID}';
1229
+ ${code}`;
1230
+ }
1231
+ };
1232
+ }
1233
+
1234
+ // src/plugin/mcpClientConfig/index.ts
1235
+ var import_node_path4 = __toESM(require("path"), 1);
1236
+
1237
+ // src/plugin/mcpClientConfig/codexConfig.ts
1238
+ var import_promises = __toESM(require("fs/promises"), 1);
1239
+ var import_node_path2 = __toESM(require("path"), 1);
1240
+ async function updateCodexMcpClientConfig(options) {
1241
+ try {
1242
+ const current = await readOptionalTextFile(options.configPath);
1243
+ const next = replaceOrAppendOwnedBlock(current, options);
1244
+ await import_promises.default.mkdir(import_node_path2.default.dirname(options.configPath), { recursive: true });
1245
+ await import_promises.default.writeFile(options.configPath, next);
1246
+ } catch (error) {
1247
+ console.warn(
1248
+ `[vite-plugin-vue-mcp-next] Failed to update Codex MCP config at ${options.configPath}: ${formatError(error)}`
1249
+ );
1250
+ }
1251
+ }
1252
+ function replaceOrAppendOwnedBlock(current, options) {
1253
+ const block = createCodexServerBlock(options);
1254
+ const matcher = createOwnedBlockMatcher(options.serverName);
1255
+ if (matcher.test(current)) {
1256
+ return current.replace(matcher, block);
1257
+ }
1258
+ const separator = current.trim() ? "\n\n" : "";
1259
+ return `${trimEndNewline(current)}${separator}${block}`;
1260
+ }
1261
+ function createCodexServerBlock(options) {
1262
+ return `${createTableHeader(options.serverName)}
1263
+ url = ${quoteTomlString(options.mcpUrl)}
1264
+ `;
1265
+ }
1266
+ function createOwnedBlockMatcher(serverName) {
1267
+ const plainHeader = escapeRegExp(`[mcp_servers.${serverName}]`);
1268
+ const quotedHeader = escapeRegExp(
1269
+ `[mcp_servers.${quoteTomlKey(serverName)}]`
1270
+ );
1271
+ return new RegExp(
1272
+ `(?:^|\\n)(?:${plainHeader}|${quotedHeader})\\n[\\s\\S]*?(?=\\n\\[|$)`
1273
+ );
1274
+ }
1275
+ function createTableHeader(serverName) {
1276
+ const key = /^[A-Za-z0-9_-]+$/.test(serverName) ? serverName : quoteTomlKey(serverName);
1277
+ return `[mcp_servers.${key}]`;
1278
+ }
1279
+ function quoteTomlKey(value) {
1280
+ return quoteTomlString(value);
1281
+ }
1282
+ function quoteTomlString(value) {
1283
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
1284
+ }
1285
+ async function readOptionalTextFile(filePath) {
1286
+ try {
1287
+ return await import_promises.default.readFile(filePath, "utf-8");
1288
+ } catch (error) {
1289
+ if (isNodeError(error) && error.code === "ENOENT") {
1290
+ return "";
1291
+ }
1292
+ throw error;
1293
+ }
1294
+ }
1295
+ function trimEndNewline(value) {
1296
+ return value.replace(/\n+$/u, "");
1297
+ }
1298
+ function escapeRegExp(value) {
1299
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1300
+ }
1301
+ function formatError(error) {
1302
+ return error instanceof Error ? error.message : String(error);
1303
+ }
1304
+ function isNodeError(error) {
1305
+ return error instanceof Error && "code" in error;
1306
+ }
1307
+
1308
+ // src/plugin/mcpClientConfig/jsonConfig.ts
1309
+ var import_promises2 = __toESM(require("fs/promises"), 1);
1310
+ var import_node_path3 = __toESM(require("path"), 1);
1311
+ async function updateJsonMcpClientConfig(options) {
1312
+ try {
1313
+ const config = await readJsonConfig(options.configPath);
1314
+ if (!isPlainRecord(config)) {
1315
+ warnConfigFailure(options, "config root must be a JSON object");
1316
+ return;
1317
+ }
1318
+ const mcpServers = isPlainRecord(config.mcpServers) ? config.mcpServers : {};
1319
+ mcpServers[options.serverName] = { url: options.mcpUrl };
1320
+ config.mcpServers = mcpServers;
1321
+ await import_promises2.default.mkdir(import_node_path3.default.dirname(options.configPath), { recursive: true });
1322
+ await import_promises2.default.writeFile(
1323
+ options.configPath,
1324
+ `${JSON.stringify(config, null, 2)}
1325
+ `
1326
+ );
1327
+ } catch (error) {
1328
+ warnConfigFailure(options, formatError2(error));
1329
+ }
1330
+ }
1331
+ async function readJsonConfig(configPath) {
1332
+ const raw = await readOptionalTextFile2(configPath);
1333
+ if (!raw.trim()) {
1334
+ return {};
1335
+ }
1336
+ return JSON.parse(raw);
1337
+ }
1338
+ async function readOptionalTextFile2(filePath) {
1339
+ try {
1340
+ return await import_promises2.default.readFile(filePath, "utf-8");
1341
+ } catch (error) {
1342
+ if (isNodeError2(error) && error.code === "ENOENT") {
1343
+ return "{}";
1344
+ }
1345
+ throw error;
1346
+ }
1347
+ }
1348
+ function isPlainRecord(value) {
1349
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1350
+ }
1351
+ function warnConfigFailure(options, reason) {
1352
+ console.warn(
1353
+ `[vite-plugin-vue-mcp-next] Failed to update ${options.clientName} MCP config at ${options.configPath}: ${reason}`
1354
+ );
1355
+ }
1356
+ function formatError2(error) {
1357
+ return error instanceof Error ? error.message : String(error);
1358
+ }
1359
+ function isNodeError2(error) {
1360
+ return error instanceof Error && "code" in error;
1361
+ }
1362
+
1363
+ // src/plugin/mcpClientConfig/index.ts
1364
+ async function updateMcpClientConfigs(root, mcpUrl, options) {
1365
+ const serverName = options.serverName;
1366
+ const jobs = [];
1367
+ if (options.cursor) {
1368
+ jobs.push(
1369
+ updateJsonMcpClientConfig({
1370
+ clientName: "Cursor",
1371
+ configPath: import_node_path4.default.join(root, ".cursor", "mcp.json"),
1372
+ mcpUrl,
1373
+ serverName
1374
+ })
1375
+ );
1376
+ }
1377
+ if (options.codex) {
1378
+ jobs.push(
1379
+ updateCodexMcpClientConfig({
1380
+ configPath: import_node_path4.default.join(root, ".codex", "config.toml"),
1381
+ mcpUrl,
1382
+ serverName
1383
+ })
1384
+ );
1385
+ }
1386
+ if (options.claudeCode) {
1387
+ jobs.push(
1388
+ updateJsonMcpClientConfig({
1389
+ clientName: "Claude Code",
1390
+ configPath: import_node_path4.default.join(root, ".mcp.json"),
1391
+ mcpUrl,
1392
+ serverName
1393
+ })
1394
+ );
1395
+ }
1396
+ if (options.trae) {
1397
+ jobs.push(
1398
+ updateJsonMcpClientConfig({
1399
+ clientName: "Trae",
1400
+ configPath: import_node_path4.default.join(root, ".trae", "mcp.json"),
1401
+ mcpUrl,
1402
+ serverName
1403
+ })
1404
+ );
1405
+ }
1406
+ await Promise.all(jobs);
1407
+ }
1408
+
1409
+ // src/plugin/createPlugin.ts
1410
+ var import_vite_dev_rpc = require("vite-dev-rpc");
1411
+ function vueMcpNext(userOptions = {}) {
1412
+ const options = mergeOptions(userOptions);
1413
+ const ctx = createVueMcpNextContext(options);
1414
+ let config;
1415
+ const runtimeInjection = createRuntimeInjectionController(
1416
+ options,
1417
+ () => config
1418
+ );
1419
+ const cdpLifecycle = createCdpLifecycleController(ctx);
1420
+ ctx.cdpLifecycle = cdpLifecycle;
1421
+ return {
1422
+ name: "vite-plugin-vue-mcp-next",
1423
+ enforce: "pre",
1424
+ apply: "serve",
1425
+ configResolved(resolvedConfig) {
1426
+ config = resolvedConfig;
1427
+ },
1428
+ async configureServer(server) {
1429
+ ctx.rpcServer = (0, import_vite_dev_rpc.createRPCServer)(
1430
+ "vite-plugin-vue-mcp-next",
1431
+ server.ws,
1432
+ createServerVueRuntimeRpc(ctx),
1433
+ {
1434
+ timeout: -1
1435
+ }
1436
+ );
1437
+ const mcpServer = createMcpServer(ctx, server);
1438
+ setupMcpTransport(options.mcpPath, mcpServer, server);
1439
+ server.ws.on(
1440
+ "vite-plugin-vue-mcp-next:page-connected",
1441
+ (payload) => {
1442
+ if (isRuntimePageTarget(payload)) {
1443
+ ctx.pages.upsert(payload);
1444
+ void cdpLifecycle.connectPage(payload);
1445
+ }
1446
+ }
1447
+ );
1448
+ server.ws.on(
1449
+ "vite-plugin-vue-mcp-next:console-record",
1450
+ (payload) => {
1451
+ if (isConsoleRecord(payload)) {
1452
+ ctx.consoleRecords.push(payload);
1453
+ }
1454
+ }
1455
+ );
1456
+ server.ws.on(
1457
+ "vite-plugin-vue-mcp-next:network-record",
1458
+ (payload) => {
1459
+ if (isNetworkRecord(payload)) {
1460
+ ctx.networkRecords.push(payload);
1461
+ }
1462
+ }
1463
+ );
1464
+ const port = String(server.config.server.port || 5173);
1465
+ const mcpUrl = `http://${options.host}:${port}${options.mcpPath}/sse`;
1466
+ const root = (0, import_vite2.searchForWorkspaceRoot)(server.config.root);
1467
+ await updateMcpClientConfigs(root, mcpUrl, options.mcpClients);
1468
+ if (options.printUrl) {
1469
+ setTimeout(() => {
1470
+ console.log(` \u279C MCP: Server is running at ${mcpUrl}`);
1471
+ }, 300);
1472
+ }
1473
+ server.httpServer?.once("close", () => {
1474
+ void cdpLifecycle.closeAll();
1475
+ });
1476
+ },
1477
+ resolveId(importee) {
1478
+ return runtimeInjection.resolveId(importee);
1479
+ },
1480
+ load(id) {
1481
+ return runtimeInjection.load(id);
1482
+ },
1483
+ transform(code, id, transformOptions) {
1484
+ return runtimeInjection.transform(code, id, transformOptions?.ssr);
1485
+ },
1486
+ transformIndexHtml(html) {
1487
+ return runtimeInjection.transformIndexHtml(html);
1488
+ }
1489
+ };
1490
+ }
1491
+ function isRuntimePageTarget(payload) {
1492
+ if (!payload || typeof payload !== "object") {
1493
+ return false;
1494
+ }
1495
+ const target = payload;
1496
+ return target.source === "runtime" && typeof target.pageId === "string" && typeof target.url === "string" && typeof target.pathname === "string" && typeof target.connected === "boolean";
1497
+ }
1498
+ function isConsoleRecord(payload) {
1499
+ if (!payload || typeof payload !== "object") {
1500
+ return false;
1501
+ }
1502
+ const record = payload;
1503
+ return typeof record.id === "string" && typeof record.pageId === "string" && record.source === "hook" && isConsoleLevel(record.level) && typeof record.message === "string" && typeof record.timestamp === "number";
1504
+ }
1505
+ function isConsoleLevel(level) {
1506
+ return level === "log" || level === "info" || level === "warn" || level === "error" || level === "debug";
1507
+ }
1508
+ function isNetworkRecord(payload) {
1509
+ if (!payload || typeof payload !== "object") {
1510
+ return false;
1511
+ }
1512
+ const record = payload;
1513
+ return typeof record.id === "string" && typeof record.pageId === "string" && record.source === "hook" && typeof record.url === "string" && typeof record.method === "string" && typeof record.startedAt === "number";
1514
+ }
1515
+ // Annotate the CommonJS export names for ESM import in node:
1516
+ 0 && (module.exports = {
1517
+ vueMcpNext
1518
+ });
1519
+ //# sourceMappingURL=index.cjs.map