@xiaou66/vite-plugin-vue-mcp-next 1.0.4 → 1.1.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/README.md +51 -0
- package/dist/index.cjs +751 -98
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +257 -0
- package/dist/index.d.ts +257 -0
- package/dist/index.js +702 -49
- package/dist/index.js.map +1 -1
- package/dist/runtime/client.cjs +585 -1
- package/dist/runtime/client.cjs.map +1 -1
- package/dist/runtime/client.js +585 -1
- package/dist/runtime/client.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,11 @@ var DEFAULT_MASK_HEADERS = [
|
|
|
55
55
|
var DEFAULT_MCP_PATH = "/__mcp";
|
|
56
56
|
var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
|
|
57
57
|
var DEFAULT_SCREENSHOT_SAVE_DIR = ".vite-mcp/screenshot";
|
|
58
|
+
var DEFAULT_PERFORMANCE_SAVE_DIR = ".vite-mcp/performance";
|
|
59
|
+
var DEFAULT_PERFORMANCE_MAX_REPORTS = 100;
|
|
60
|
+
var DEFAULT_PERFORMANCE_MAX_DURATION_MS = 3e4;
|
|
61
|
+
var DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS = 250;
|
|
62
|
+
var DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS = 50;
|
|
58
63
|
var MCP_TOOL_NAMES = {
|
|
59
64
|
listPages: "list_pages",
|
|
60
65
|
reloadPage: "reload_page",
|
|
@@ -67,6 +72,11 @@ var MCP_TOOL_NAMES = {
|
|
|
67
72
|
getNetworkRequests: "get_network_requests",
|
|
68
73
|
getNetworkRequestDetail: "get_network_request_detail",
|
|
69
74
|
clearNetworkRequests: "clear_network_requests",
|
|
75
|
+
recordPerformance: "record_performance",
|
|
76
|
+
startPerformanceRecording: "start_performance_recording",
|
|
77
|
+
stopPerformanceRecording: "stop_performance_recording",
|
|
78
|
+
getPerformanceReport: "get_performance_report",
|
|
79
|
+
takeHeapSnapshot: "take_heap_snapshot",
|
|
70
80
|
getComponentTree: "get_component_tree",
|
|
71
81
|
getComponentState: "get_component_state",
|
|
72
82
|
editComponentState: "edit_component_state",
|
|
@@ -135,6 +145,19 @@ var DEFAULT_OPTIONS = {
|
|
|
135
145
|
options: {},
|
|
136
146
|
plugins: []
|
|
137
147
|
}
|
|
148
|
+
},
|
|
149
|
+
performance: {
|
|
150
|
+
mode: "auto",
|
|
151
|
+
maxDurationMs: DEFAULT_PERFORMANCE_MAX_DURATION_MS,
|
|
152
|
+
sampleIntervalMs: DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS,
|
|
153
|
+
longTaskThresholdMs: DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS,
|
|
154
|
+
saveDir: DEFAULT_PERFORMANCE_SAVE_DIR,
|
|
155
|
+
memory: {
|
|
156
|
+
enabled: true
|
|
157
|
+
},
|
|
158
|
+
stacks: {
|
|
159
|
+
enabled: true
|
|
160
|
+
}
|
|
138
161
|
}
|
|
139
162
|
};
|
|
140
163
|
function mergeMcpClientOptions(cursorConfig, mcpClients) {
|
|
@@ -204,6 +227,18 @@ function mergeOptions(options = {}) {
|
|
|
204
227
|
...DEFAULT_OPTIONS.screenshot.snapdom.plugins
|
|
205
228
|
]
|
|
206
229
|
}
|
|
230
|
+
},
|
|
231
|
+
performance: {
|
|
232
|
+
...DEFAULT_OPTIONS.performance,
|
|
233
|
+
...options.performance,
|
|
234
|
+
memory: {
|
|
235
|
+
...DEFAULT_OPTIONS.performance.memory,
|
|
236
|
+
...options.performance?.memory
|
|
237
|
+
},
|
|
238
|
+
stacks: {
|
|
239
|
+
...DEFAULT_OPTIONS.performance.stacks,
|
|
240
|
+
...options.performance?.stacks
|
|
241
|
+
}
|
|
207
242
|
}
|
|
208
243
|
};
|
|
209
244
|
}
|
|
@@ -299,7 +334,11 @@ function createVueMcpNextContext(options) {
|
|
|
299
334
|
rpcServer: void 0,
|
|
300
335
|
pages: createPageTargetRegistry(),
|
|
301
336
|
consoleRecords: createRingBuffer(options.console.maxRecords),
|
|
302
|
-
networkRecords: createRingBuffer(options.network.maxRecords)
|
|
337
|
+
networkRecords: createRingBuffer(options.network.maxRecords),
|
|
338
|
+
performanceReports: createRingBuffer(
|
|
339
|
+
DEFAULT_PERFORMANCE_MAX_REPORTS
|
|
340
|
+
),
|
|
341
|
+
performanceSessions: /* @__PURE__ */ new Map()
|
|
303
342
|
};
|
|
304
343
|
}
|
|
305
344
|
|
|
@@ -417,13 +456,13 @@ async function requestRuntimeData(ctx, trigger) {
|
|
|
417
456
|
return { ok: false, error: "runtime bridge is not connected" };
|
|
418
457
|
}
|
|
419
458
|
const event = (0, import_nanoid.nanoid)();
|
|
420
|
-
return new Promise((
|
|
459
|
+
return new Promise((resolve2) => {
|
|
421
460
|
const timeout = setTimeout(() => {
|
|
422
|
-
|
|
461
|
+
resolve2({ ok: false, error: "runtime bridge response timed out" });
|
|
423
462
|
}, 5e3);
|
|
424
463
|
ctx.hooks.hookOnce(event, (data) => {
|
|
425
464
|
clearTimeout(timeout);
|
|
426
|
-
|
|
465
|
+
resolve2(data);
|
|
427
466
|
});
|
|
428
467
|
trigger(event);
|
|
429
468
|
});
|
|
@@ -702,12 +741,598 @@ function registerNetworkTools(server, ctx) {
|
|
|
702
741
|
);
|
|
703
742
|
}
|
|
704
743
|
|
|
705
|
-
// src/mcp/tools/
|
|
744
|
+
// src/mcp/tools/performance.ts
|
|
706
745
|
var import_zod5 = require("zod");
|
|
707
746
|
|
|
747
|
+
// src/performance/summary.ts
|
|
748
|
+
function buildPerformanceSummary(input) {
|
|
749
|
+
const memory = buildMemorySummary(input.memorySamples);
|
|
750
|
+
const blockedTimeMs = input.longTasks.reduce((total, task) => {
|
|
751
|
+
return total + Math.max(0, task.durationMs - DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS);
|
|
752
|
+
}, 0);
|
|
753
|
+
const longTaskCount = input.longTasks.length;
|
|
754
|
+
const durations = input.longTasks.map((task) => task.durationMs);
|
|
755
|
+
const maxTaskDurationMs = durations.length ? Math.max(...durations) : 0;
|
|
756
|
+
const averageTaskDurationMs = durations.length ? Math.round(
|
|
757
|
+
durations.reduce((total, duration) => total + duration, 0) / durations.length
|
|
758
|
+
) : void 0;
|
|
759
|
+
const suspectedJank = blockedTimeMs > 0 || memory.trend === "growing" || longTaskCount > 0;
|
|
760
|
+
const severity = resolveSeverity({
|
|
761
|
+
blockedTimeMs,
|
|
762
|
+
longTaskCount,
|
|
763
|
+
memoryTrend: memory.trend
|
|
764
|
+
});
|
|
765
|
+
return {
|
|
766
|
+
blockedTimeMs,
|
|
767
|
+
longTaskCount,
|
|
768
|
+
maxTaskDurationMs,
|
|
769
|
+
averageTaskDurationMs,
|
|
770
|
+
suspectedJank,
|
|
771
|
+
severity
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
function buildMemorySummary(samples) {
|
|
775
|
+
const first = samples[0]?.usedJSHeapSize;
|
|
776
|
+
const last = samples.at(-1)?.usedJSHeapSize;
|
|
777
|
+
const peak = samples.reduce((currentPeak, sample) => {
|
|
778
|
+
if (typeof sample.usedJSHeapSize !== "number") {
|
|
779
|
+
return currentPeak;
|
|
780
|
+
}
|
|
781
|
+
return Math.max(currentPeak, sample.usedJSHeapSize);
|
|
782
|
+
}, 0);
|
|
783
|
+
const trend = resolveMemoryTrend(first, last);
|
|
784
|
+
return {
|
|
785
|
+
samples,
|
|
786
|
+
initialUsedJSHeapSize: first,
|
|
787
|
+
finalUsedJSHeapSize: last,
|
|
788
|
+
peakUsedJSHeapSize: peak || void 0,
|
|
789
|
+
deltaUsedJSHeapSize: typeof first === "number" && typeof last === "number" ? last - first : void 0,
|
|
790
|
+
trend
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function buildStackSummary(frames, options = {}) {
|
|
794
|
+
return {
|
|
795
|
+
topFrames: [...frames].sort(sortByHotness).slice(0, 10),
|
|
796
|
+
rawProfilePath: options.rawProfilePath,
|
|
797
|
+
limitation: options.limitation
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
function resolveSeverity(input) {
|
|
801
|
+
if (input.blockedTimeMs >= 1e3 || input.longTaskCount >= 10) {
|
|
802
|
+
return "critical";
|
|
803
|
+
}
|
|
804
|
+
if (input.blockedTimeMs > 0 || input.memoryTrend === "growing") {
|
|
805
|
+
return "warning";
|
|
806
|
+
}
|
|
807
|
+
return "ok";
|
|
808
|
+
}
|
|
809
|
+
function resolveMemoryTrend(first, last) {
|
|
810
|
+
if (typeof first !== "number" || typeof last !== "number") {
|
|
811
|
+
return "unknown";
|
|
812
|
+
}
|
|
813
|
+
if (last > first) {
|
|
814
|
+
return "growing";
|
|
815
|
+
}
|
|
816
|
+
return "stable";
|
|
817
|
+
}
|
|
818
|
+
function sortByHotness(left, right) {
|
|
819
|
+
return compareNumber(right.totalTimeMs, left.totalTimeMs) || compareNumber(right.selfTimeMs, left.selfTimeMs) || compareNumber(right.hitCount, left.hitCount);
|
|
820
|
+
}
|
|
821
|
+
function compareNumber(left, right) {
|
|
822
|
+
return (left ?? -1) - (right ?? -1);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/performance/output.ts
|
|
826
|
+
var import_promises = require("fs/promises");
|
|
827
|
+
var import_node_path = require("path");
|
|
828
|
+
var import_nanoid2 = require("nanoid");
|
|
829
|
+
async function writePerformanceArtifact(options) {
|
|
830
|
+
const root = (0, import_node_path.resolve)(options.root ?? process.cwd());
|
|
831
|
+
const dir = resolveOutputDirectory(root, options.saveDir);
|
|
832
|
+
const path8 = (0, import_node_path.resolve)(dir, createSafeFileName(options.fileName));
|
|
833
|
+
const data = typeof options.data === "string" ? Buffer.from(options.data) : options.data;
|
|
834
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
835
|
+
await (0, import_promises.writeFile)(path8, data);
|
|
836
|
+
return {
|
|
837
|
+
kind: options.kind,
|
|
838
|
+
path: path8,
|
|
839
|
+
relativePath: (0, import_node_path.relative)(root, path8),
|
|
840
|
+
byteLength: data.byteLength,
|
|
841
|
+
source: "cdp"
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function resolveOutputDirectory(root, saveDir) {
|
|
845
|
+
return (0, import_node_path.resolve)(root, saveDir);
|
|
846
|
+
}
|
|
847
|
+
function createSafeFileName(fileName) {
|
|
848
|
+
const trimmed = fileName.trim();
|
|
849
|
+
if (!trimmed) {
|
|
850
|
+
return `${String(Date.now())}-${(0, import_nanoid2.nanoid)()}`;
|
|
851
|
+
}
|
|
852
|
+
const suffix = (0, import_nanoid2.nanoid)(6);
|
|
853
|
+
const dotIndex = trimmed.lastIndexOf(".");
|
|
854
|
+
if (dotIndex === -1) {
|
|
855
|
+
return `${trimmed}-${suffix}`;
|
|
856
|
+
}
|
|
857
|
+
const base = trimmed.slice(0, dotIndex);
|
|
858
|
+
const extension = trimmed.slice(dotIndex);
|
|
859
|
+
return `${base}-${suffix}${extension}`;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// src/cdp/cdpPerformance.ts
|
|
863
|
+
async function recordCdpPerformance(options) {
|
|
864
|
+
const session = await startCdpPerformanceRecording(options);
|
|
865
|
+
await waitForDuration(options.durationMs);
|
|
866
|
+
return stopCdpPerformanceRecording({
|
|
867
|
+
client: options.client,
|
|
868
|
+
session
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
async function startCdpPerformanceRecording(options) {
|
|
872
|
+
await options.client.Performance.enable();
|
|
873
|
+
await options.client.Profiler.enable();
|
|
874
|
+
await options.client.Profiler.start();
|
|
875
|
+
return {
|
|
876
|
+
recordingId: createRecordingId(options.pageId),
|
|
877
|
+
pageId: options.pageId,
|
|
878
|
+
startedAt: Date.now(),
|
|
879
|
+
includeMemory: options.includeMemory,
|
|
880
|
+
includeStacks: options.includeStacks,
|
|
881
|
+
saveDir: options.saveDir
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
async function stopCdpPerformanceRecording(options) {
|
|
885
|
+
const endedAt = Date.now();
|
|
886
|
+
const [metricsResult, profileResult] = await Promise.all([
|
|
887
|
+
options.client.Performance.getMetrics(),
|
|
888
|
+
options.client.Profiler.stop()
|
|
889
|
+
]);
|
|
890
|
+
const metrics = toMetricMap(metricsResult.metrics);
|
|
891
|
+
const longTasks = toLongTaskRecords(metrics);
|
|
892
|
+
const memorySamples = options.session.includeMemory ? [toMemorySample(metrics)] : [];
|
|
893
|
+
const memory = options.session.includeMemory ? buildMemorySummary(memorySamples) : void 0;
|
|
894
|
+
const stacks = options.session.includeStacks ? buildStackSummary(aggregateCpuProfile(profileResult.profile)) : void 0;
|
|
895
|
+
const artifact = await writeCpuProfileArtifact(
|
|
896
|
+
{
|
|
897
|
+
pageId: options.session.pageId,
|
|
898
|
+
saveDir: options.session.saveDir
|
|
899
|
+
},
|
|
900
|
+
profileResult.profile
|
|
901
|
+
);
|
|
902
|
+
const report = {
|
|
903
|
+
recordingId: options.session.recordingId,
|
|
904
|
+
pageId: options.session.pageId,
|
|
905
|
+
source: "cdp",
|
|
906
|
+
startedAt: options.session.startedAt,
|
|
907
|
+
endedAt,
|
|
908
|
+
durationMs: endedAt - options.session.startedAt,
|
|
909
|
+
summary: buildPerformanceSummary({
|
|
910
|
+
longTasks,
|
|
911
|
+
memorySamples
|
|
912
|
+
}),
|
|
913
|
+
longTasks,
|
|
914
|
+
memory,
|
|
915
|
+
stacks,
|
|
916
|
+
artifacts: [artifact],
|
|
917
|
+
limitations: [
|
|
918
|
+
"CDP path returns sampled CPU profile data, not a full instruction trace"
|
|
919
|
+
]
|
|
920
|
+
};
|
|
921
|
+
return report;
|
|
922
|
+
}
|
|
923
|
+
async function takeHeapSnapshot(options) {
|
|
924
|
+
const chunks = [];
|
|
925
|
+
await options.client.HeapProfiler.enable();
|
|
926
|
+
options.client.HeapProfiler.addHeapSnapshotChunk((event) => {
|
|
927
|
+
const payload = event;
|
|
928
|
+
if (payload.chunk) {
|
|
929
|
+
chunks.push(payload.chunk);
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
await options.client.HeapProfiler.takeHeapSnapshot({
|
|
933
|
+
reportProgress: false
|
|
934
|
+
});
|
|
935
|
+
const artifact = await writePerformanceArtifact({
|
|
936
|
+
root: process.cwd(),
|
|
937
|
+
saveDir: options.saveDir,
|
|
938
|
+
fileName: `${options.pageId}-heap-snapshot.heapsnapshot`,
|
|
939
|
+
kind: "heap-snapshot",
|
|
940
|
+
data: Buffer.from(chunks.join(""))
|
|
941
|
+
});
|
|
942
|
+
return artifact;
|
|
943
|
+
}
|
|
944
|
+
function createRecordingId(pageId) {
|
|
945
|
+
return `cdp-${pageId}-${String(Date.now())}`;
|
|
946
|
+
}
|
|
947
|
+
function waitForDuration(durationMs) {
|
|
948
|
+
return new Promise((resolve2) => {
|
|
949
|
+
setTimeout(() => {
|
|
950
|
+
resolve2();
|
|
951
|
+
}, durationMs);
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
function toMetricMap(metrics) {
|
|
955
|
+
return new Map(metrics.map((metric) => [metric.name, metric.value]));
|
|
956
|
+
}
|
|
957
|
+
function toLongTaskRecords(metrics) {
|
|
958
|
+
const taskDuration = metrics.get("TaskDuration") ?? 0;
|
|
959
|
+
if (taskDuration <= 0) {
|
|
960
|
+
return [];
|
|
961
|
+
}
|
|
962
|
+
return [
|
|
963
|
+
{
|
|
964
|
+
startTime: 0,
|
|
965
|
+
durationMs: taskDuration,
|
|
966
|
+
name: "TaskDuration",
|
|
967
|
+
source: "cpu-profile"
|
|
968
|
+
}
|
|
969
|
+
];
|
|
970
|
+
}
|
|
971
|
+
function toMemorySample(metrics) {
|
|
972
|
+
return {
|
|
973
|
+
timestamp: Date.now(),
|
|
974
|
+
usedJSHeapSize: metrics.get("JSHeapUsedSize"),
|
|
975
|
+
totalJSHeapSize: metrics.get("JSHeapTotalSize"),
|
|
976
|
+
jsHeapSizeLimit: metrics.get("JSHeapSizeLimit")
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
function aggregateCpuProfile(profile) {
|
|
980
|
+
const nodes = profile.nodes ?? [];
|
|
981
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
982
|
+
const nodeIndex = /* @__PURE__ */ new Map();
|
|
983
|
+
nodes.forEach((node) => nodeIndex.set(node.id, node));
|
|
984
|
+
(profile.samples ?? []).forEach((nodeId, index) => {
|
|
985
|
+
const node = nodeIndex.get(nodeId);
|
|
986
|
+
if (!node) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const delta = profile.timeDeltas?.[index] ?? 0;
|
|
990
|
+
const current = nodeMap.get(nodeId) ?? {
|
|
991
|
+
functionName: node.callFrame.functionName || "<anonymous>",
|
|
992
|
+
url: node.callFrame.url,
|
|
993
|
+
lineNumber: node.callFrame.lineNumber,
|
|
994
|
+
columnNumber: node.callFrame.columnNumber,
|
|
995
|
+
selfTimeMs: 0,
|
|
996
|
+
totalTimeMs: 0,
|
|
997
|
+
hitCount: 0
|
|
998
|
+
};
|
|
999
|
+
nodeMap.set(nodeId, {
|
|
1000
|
+
...current,
|
|
1001
|
+
selfTimeMs: current.selfTimeMs + delta,
|
|
1002
|
+
totalTimeMs: current.totalTimeMs + delta,
|
|
1003
|
+
hitCount: current.hitCount + 1
|
|
1004
|
+
});
|
|
1005
|
+
});
|
|
1006
|
+
return [...nodeMap.values()];
|
|
1007
|
+
}
|
|
1008
|
+
async function writeCpuProfileArtifact(options, profile) {
|
|
1009
|
+
return writePerformanceArtifact({
|
|
1010
|
+
root: process.cwd(),
|
|
1011
|
+
saveDir: options.saveDir ?? ".vite-mcp/performance",
|
|
1012
|
+
fileName: `${options.pageId}-cpu-profile.cpuprofile`,
|
|
1013
|
+
kind: "cpu-profile",
|
|
1014
|
+
data: Buffer.from(JSON.stringify(profile, null, 2))
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// src/mcp/tools/performance.ts
|
|
1019
|
+
var PERFORMANCE_NOT_AVAILABLE_ERROR = "Performance diagnostics are disabled by configuration";
|
|
1020
|
+
var activeCdpPerformanceClients = /* @__PURE__ */ new Map();
|
|
1021
|
+
function registerPerformanceTools(server, ctx) {
|
|
1022
|
+
server.registerTool(
|
|
1023
|
+
MCP_TOOL_NAMES.recordPerformance,
|
|
1024
|
+
{
|
|
1025
|
+
description: "Record a performance sample for the selected page.",
|
|
1026
|
+
inputSchema: {
|
|
1027
|
+
pageId: import_zod5.z.string().optional(),
|
|
1028
|
+
durationMs: import_zod5.z.number().optional(),
|
|
1029
|
+
includeMemory: import_zod5.z.boolean().optional(),
|
|
1030
|
+
includeStacks: import_zod5.z.boolean().optional()
|
|
1031
|
+
}
|
|
1032
|
+
},
|
|
1033
|
+
async (input) => handleRecordPerformance(ctx, input)
|
|
1034
|
+
);
|
|
1035
|
+
server.registerTool(
|
|
1036
|
+
MCP_TOOL_NAMES.startPerformanceRecording,
|
|
1037
|
+
{
|
|
1038
|
+
description: "Start a performance recording session.",
|
|
1039
|
+
inputSchema: {
|
|
1040
|
+
pageId: import_zod5.z.string().optional(),
|
|
1041
|
+
includeMemory: import_zod5.z.boolean().optional(),
|
|
1042
|
+
includeStacks: import_zod5.z.boolean().optional()
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
async (input) => handleStartPerformanceRecording(ctx, input)
|
|
1046
|
+
);
|
|
1047
|
+
server.registerTool(
|
|
1048
|
+
MCP_TOOL_NAMES.stopPerformanceRecording,
|
|
1049
|
+
{
|
|
1050
|
+
description: "Stop a performance recording session.",
|
|
1051
|
+
inputSchema: {
|
|
1052
|
+
recordingId: import_zod5.z.string()
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
async (input) => handleStopPerformanceRecording(ctx, input)
|
|
1056
|
+
);
|
|
1057
|
+
server.registerTool(
|
|
1058
|
+
MCP_TOOL_NAMES.getPerformanceReport,
|
|
1059
|
+
{
|
|
1060
|
+
description: "Get cached performance reports and active sessions.",
|
|
1061
|
+
inputSchema: {
|
|
1062
|
+
pageId: import_zod5.z.string().optional(),
|
|
1063
|
+
recordingId: import_zod5.z.string().optional(),
|
|
1064
|
+
limit: import_zod5.z.number().optional()
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
(input) => handleGetPerformanceReport(ctx, input)
|
|
1068
|
+
);
|
|
1069
|
+
server.registerTool(
|
|
1070
|
+
MCP_TOOL_NAMES.takeHeapSnapshot,
|
|
1071
|
+
{
|
|
1072
|
+
description: "Take a heap snapshot with CDP.",
|
|
1073
|
+
inputSchema: {
|
|
1074
|
+
pageId: import_zod5.z.string().optional()
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
async (input) => handleTakeHeapSnapshot(ctx, input)
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
function appendPerformanceReport(ctx, report) {
|
|
1081
|
+
if (ctx.performanceReports.all().some((item) => item.recordingId === report.recordingId)) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
ctx.performanceReports.push(report);
|
|
1085
|
+
}
|
|
1086
|
+
async function handleRecordPerformance(ctx, input) {
|
|
1087
|
+
const durationMs = input.durationMs ?? ctx.options.performance.maxDurationMs;
|
|
1088
|
+
const includeMemory = input.includeMemory ?? ctx.options.performance.memory.enabled;
|
|
1089
|
+
const includeStacks = input.includeStacks ?? ctx.options.performance.stacks.enabled;
|
|
1090
|
+
if (ctx.options.performance.mode === "off") {
|
|
1091
|
+
return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR);
|
|
1092
|
+
}
|
|
1093
|
+
if (ctx.options.performance.mode !== "hook") {
|
|
1094
|
+
const cdpResult = await connectPerformanceCdp(ctx, input.pageId);
|
|
1095
|
+
const cdp = cdpResult.cdp;
|
|
1096
|
+
if (cdp) {
|
|
1097
|
+
try {
|
|
1098
|
+
const report = await recordCdpPerformance({
|
|
1099
|
+
client: cdp.client,
|
|
1100
|
+
pageId: input.pageId ?? "cdp",
|
|
1101
|
+
durationMs,
|
|
1102
|
+
includeMemory,
|
|
1103
|
+
includeStacks,
|
|
1104
|
+
saveDir: ctx.options.performance.saveDir
|
|
1105
|
+
});
|
|
1106
|
+
appendPerformanceReport(ctx, report);
|
|
1107
|
+
return createToolResponse(toStructuredRecord(report));
|
|
1108
|
+
} finally {
|
|
1109
|
+
await closeCdpClient(cdp.client);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
if (ctx.options.performance.mode === "cdp") {
|
|
1113
|
+
return createToolError(
|
|
1114
|
+
formatCdpUnavailableError(
|
|
1115
|
+
"CDP performance collection is unavailable",
|
|
1116
|
+
cdpResult.error
|
|
1117
|
+
)
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
const result = await requestRuntimeData(ctx, (event) => {
|
|
1122
|
+
void ctx.rpcServer?.recordPerformance({
|
|
1123
|
+
event,
|
|
1124
|
+
durationMs,
|
|
1125
|
+
includeMemory,
|
|
1126
|
+
includeStacks
|
|
1127
|
+
});
|
|
1128
|
+
});
|
|
1129
|
+
if (isPerformanceReport(result)) {
|
|
1130
|
+
appendPerformanceReport(ctx, result);
|
|
1131
|
+
}
|
|
1132
|
+
if (isPlainRecord(result)) {
|
|
1133
|
+
return createToolResponse(toStructuredRecord(result));
|
|
1134
|
+
}
|
|
1135
|
+
return createToolError("runtime bridge returned an invalid response");
|
|
1136
|
+
}
|
|
1137
|
+
async function handleStartPerformanceRecording(ctx, input) {
|
|
1138
|
+
const includeMemory = input.includeMemory ?? ctx.options.performance.memory.enabled;
|
|
1139
|
+
const includeStacks = input.includeStacks ?? ctx.options.performance.stacks.enabled;
|
|
1140
|
+
if (ctx.options.performance.mode === "off") {
|
|
1141
|
+
return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR);
|
|
1142
|
+
}
|
|
1143
|
+
if (ctx.options.performance.mode !== "hook") {
|
|
1144
|
+
const cdpResult = await connectPerformanceCdp(ctx, input.pageId);
|
|
1145
|
+
const cdp = cdpResult.cdp;
|
|
1146
|
+
if (cdp) {
|
|
1147
|
+
try {
|
|
1148
|
+
const session = await startCdpPerformanceRecording({
|
|
1149
|
+
client: cdp.client,
|
|
1150
|
+
pageId: input.pageId ?? "cdp",
|
|
1151
|
+
includeMemory,
|
|
1152
|
+
includeStacks,
|
|
1153
|
+
saveDir: ctx.options.performance.saveDir
|
|
1154
|
+
});
|
|
1155
|
+
ctx.performanceSessions.set(session.recordingId, {
|
|
1156
|
+
recordingId: session.recordingId,
|
|
1157
|
+
pageId: session.pageId,
|
|
1158
|
+
source: "cdp",
|
|
1159
|
+
startedAt: session.startedAt,
|
|
1160
|
+
includeMemory,
|
|
1161
|
+
includeStacks,
|
|
1162
|
+
mode: ctx.options.performance.mode
|
|
1163
|
+
});
|
|
1164
|
+
activeCdpPerformanceClients.set(session.recordingId, cdp.client);
|
|
1165
|
+
return createToolResponse(
|
|
1166
|
+
toStructuredRecord({
|
|
1167
|
+
...session,
|
|
1168
|
+
source: "cdp"
|
|
1169
|
+
})
|
|
1170
|
+
);
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
await closeCdpClient(cdp.client);
|
|
1173
|
+
return createToolError(
|
|
1174
|
+
error instanceof Error ? error.message : String(error)
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
if (ctx.options.performance.mode === "cdp") {
|
|
1179
|
+
return createToolError(
|
|
1180
|
+
formatCdpUnavailableError(
|
|
1181
|
+
"CDP performance collection is unavailable",
|
|
1182
|
+
cdpResult.error
|
|
1183
|
+
)
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
const result = await requestRuntimeData(ctx, (event) => {
|
|
1188
|
+
void ctx.rpcServer?.startPerformanceRecording({
|
|
1189
|
+
event,
|
|
1190
|
+
includeMemory,
|
|
1191
|
+
includeStacks
|
|
1192
|
+
});
|
|
1193
|
+
});
|
|
1194
|
+
if (isPerformanceStartResult(result)) {
|
|
1195
|
+
ctx.performanceSessions.set(result.recordingId, {
|
|
1196
|
+
recordingId: result.recordingId,
|
|
1197
|
+
pageId: input.pageId ?? "runtime",
|
|
1198
|
+
source: "hook",
|
|
1199
|
+
startedAt: result.startedAt,
|
|
1200
|
+
includeMemory,
|
|
1201
|
+
includeStacks,
|
|
1202
|
+
mode: ctx.options.performance.mode
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
if (isPlainRecord(result)) {
|
|
1206
|
+
return createToolResponse(toStructuredRecord(result));
|
|
1207
|
+
}
|
|
1208
|
+
return createToolError("runtime bridge returned an invalid response");
|
|
1209
|
+
}
|
|
1210
|
+
async function handleStopPerformanceRecording(ctx, input) {
|
|
1211
|
+
const session = ctx.performanceSessions.get(input.recordingId);
|
|
1212
|
+
if (!session) {
|
|
1213
|
+
return createToolError(`Performance recording not found: ${input.recordingId}`);
|
|
1214
|
+
}
|
|
1215
|
+
try {
|
|
1216
|
+
if (session.source === "cdp") {
|
|
1217
|
+
const client = activeCdpPerformanceClients.get(input.recordingId);
|
|
1218
|
+
if (!client) {
|
|
1219
|
+
return createToolError(
|
|
1220
|
+
`CDP client not found for recording: ${input.recordingId}`
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
const report = await stopCdpPerformanceRecording({
|
|
1224
|
+
client,
|
|
1225
|
+
session
|
|
1226
|
+
});
|
|
1227
|
+
appendPerformanceReport(ctx, report);
|
|
1228
|
+
return createToolResponse(toStructuredRecord(report));
|
|
1229
|
+
}
|
|
1230
|
+
const result = await requestRuntimeData(ctx, (event) => {
|
|
1231
|
+
void ctx.rpcServer?.stopPerformanceRecording({
|
|
1232
|
+
event,
|
|
1233
|
+
recordingId: input.recordingId
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1236
|
+
if (isPerformanceReport(result)) {
|
|
1237
|
+
appendPerformanceReport(ctx, result);
|
|
1238
|
+
}
|
|
1239
|
+
if (isPlainRecord(result)) {
|
|
1240
|
+
return createToolResponse(toStructuredRecord(result));
|
|
1241
|
+
}
|
|
1242
|
+
return createToolError("runtime bridge returned an invalid response");
|
|
1243
|
+
} finally {
|
|
1244
|
+
ctx.performanceSessions.delete(input.recordingId);
|
|
1245
|
+
const client = activeCdpPerformanceClients.get(input.recordingId);
|
|
1246
|
+
if (client) {
|
|
1247
|
+
activeCdpPerformanceClients.delete(input.recordingId);
|
|
1248
|
+
await closeCdpClient(client);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function handleGetPerformanceReport(ctx, input) {
|
|
1253
|
+
const reports = ctx.performanceReports.all().filter((report) => !input.pageId || report.pageId === input.pageId).filter(
|
|
1254
|
+
(report) => !input.recordingId || report.recordingId === input.recordingId
|
|
1255
|
+
);
|
|
1256
|
+
const limit = input.limit ?? reports.length;
|
|
1257
|
+
return createToolResponse(toStructuredRecord({
|
|
1258
|
+
report: reports.at(-1) ?? null,
|
|
1259
|
+
reports: reports.slice(-limit),
|
|
1260
|
+
sessions: [...ctx.performanceSessions.values()].filter(
|
|
1261
|
+
(session) => (!input.pageId || session.pageId === input.pageId) && (!input.recordingId || session.recordingId === input.recordingId)
|
|
1262
|
+
)
|
|
1263
|
+
}));
|
|
1264
|
+
}
|
|
1265
|
+
async function handleTakeHeapSnapshot(ctx, input) {
|
|
1266
|
+
if (ctx.options.performance.mode === "off" || ctx.options.performance.mode === "hook") {
|
|
1267
|
+
return createToolError(PERFORMANCE_NOT_AVAILABLE_ERROR);
|
|
1268
|
+
}
|
|
1269
|
+
const cdpResult = await connectPerformanceCdp(ctx, input.pageId);
|
|
1270
|
+
const cdp = cdpResult.cdp;
|
|
1271
|
+
if (!cdp) {
|
|
1272
|
+
return createToolError(
|
|
1273
|
+
formatCdpUnavailableError(
|
|
1274
|
+
"CDP heap snapshot is unavailable",
|
|
1275
|
+
cdpResult.error
|
|
1276
|
+
)
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
try {
|
|
1280
|
+
return createToolResponse(
|
|
1281
|
+
toStructuredRecord(await takeHeapSnapshot({
|
|
1282
|
+
client: cdp.client,
|
|
1283
|
+
pageId: input.pageId ?? "cdp",
|
|
1284
|
+
saveDir: ctx.options.performance.saveDir
|
|
1285
|
+
}))
|
|
1286
|
+
);
|
|
1287
|
+
} finally {
|
|
1288
|
+
await closeCdpClient(cdp.client);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
async function connectPerformanceCdp(ctx, pageId) {
|
|
1292
|
+
try {
|
|
1293
|
+
return { cdp: await connectCdpForPage(ctx, pageId) };
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
return {
|
|
1296
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function formatCdpUnavailableError(message, reason) {
|
|
1301
|
+
if (!reason) {
|
|
1302
|
+
return message;
|
|
1303
|
+
}
|
|
1304
|
+
return `${message}: ${reason}`;
|
|
1305
|
+
}
|
|
1306
|
+
function isPerformanceReport(value) {
|
|
1307
|
+
if (!value || typeof value !== "object") {
|
|
1308
|
+
return false;
|
|
1309
|
+
}
|
|
1310
|
+
const report = value;
|
|
1311
|
+
return typeof report.recordingId === "string" && typeof report.pageId === "string" && (report.source === "hook" || report.source === "cdp") && typeof report.startedAt === "number" && typeof report.endedAt === "number" && typeof report.durationMs === "number" && Boolean(report.summary) && Array.isArray(report.longTasks) && Array.isArray(report.limitations);
|
|
1312
|
+
}
|
|
1313
|
+
function isPerformanceStartResult(value) {
|
|
1314
|
+
if (!value || typeof value !== "object") {
|
|
1315
|
+
return false;
|
|
1316
|
+
}
|
|
1317
|
+
const result = value;
|
|
1318
|
+
return typeof result.recordingId === "string" && typeof result.startedAt === "number";
|
|
1319
|
+
}
|
|
1320
|
+
function isPlainRecord(value) {
|
|
1321
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1322
|
+
}
|
|
1323
|
+
function toStructuredRecord(value) {
|
|
1324
|
+
if (isPlainRecord(value)) {
|
|
1325
|
+
return value;
|
|
1326
|
+
}
|
|
1327
|
+
return {};
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// src/mcp/tools/pages.ts
|
|
1331
|
+
var import_zod6 = require("zod");
|
|
1332
|
+
|
|
708
1333
|
// src/plugin/entryDiscovery.ts
|
|
709
1334
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
710
|
-
var
|
|
1335
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
711
1336
|
var import_vite = require("vite");
|
|
712
1337
|
function discoverHtmlEntries(server) {
|
|
713
1338
|
const root = server.config.root;
|
|
@@ -720,7 +1345,7 @@ function walkHtmlEntries(root, dir, entries) {
|
|
|
720
1345
|
if (item.name === "node_modules" || item.name.startsWith(".")) {
|
|
721
1346
|
continue;
|
|
722
1347
|
}
|
|
723
|
-
const fullPath =
|
|
1348
|
+
const fullPath = import_node_path2.default.join(dir, item.name);
|
|
724
1349
|
if (item.isDirectory()) {
|
|
725
1350
|
walkHtmlEntries(root, fullPath, entries);
|
|
726
1351
|
continue;
|
|
@@ -728,10 +1353,10 @@ function walkHtmlEntries(root, dir, entries) {
|
|
|
728
1353
|
if (!item.isFile() || !item.name.endsWith(".html")) {
|
|
729
1354
|
continue;
|
|
730
1355
|
}
|
|
731
|
-
const
|
|
1356
|
+
const relative2 = (0, import_vite.normalizePath)(import_node_path2.default.relative(root, fullPath));
|
|
732
1357
|
entries.push({
|
|
733
|
-
file:
|
|
734
|
-
pathname:
|
|
1358
|
+
file: relative2,
|
|
1359
|
+
pathname: relative2 === "index.html" ? "/" : `/${relative2}`
|
|
735
1360
|
});
|
|
736
1361
|
}
|
|
737
1362
|
}
|
|
@@ -743,7 +1368,7 @@ function registerPageTools(server, ctx, vite) {
|
|
|
743
1368
|
{
|
|
744
1369
|
description: "List Vite page entries and connected runtime/CDP targets.",
|
|
745
1370
|
inputSchema: {
|
|
746
|
-
includeDisconnected:
|
|
1371
|
+
includeDisconnected: import_zod6.z.boolean().optional()
|
|
747
1372
|
}
|
|
748
1373
|
},
|
|
749
1374
|
async (input) => {
|
|
@@ -766,8 +1391,8 @@ function registerPageTools(server, ctx, vite) {
|
|
|
766
1391
|
{
|
|
767
1392
|
description: "Reload the selected page. CDP uses ignoreCache; Runtime Hook falls back to normal reload.",
|
|
768
1393
|
inputSchema: {
|
|
769
|
-
pageId:
|
|
770
|
-
ignoreCache:
|
|
1394
|
+
pageId: import_zod6.z.string().optional(),
|
|
1395
|
+
ignoreCache: import_zod6.z.boolean().optional()
|
|
771
1396
|
}
|
|
772
1397
|
},
|
|
773
1398
|
async (input) => {
|
|
@@ -826,16 +1451,16 @@ function resolveRuntimeReloadTarget(ctx, pageId) {
|
|
|
826
1451
|
function waitForRuntimePageReconnect(ctx) {
|
|
827
1452
|
let timeout;
|
|
828
1453
|
let cleanup;
|
|
829
|
-
const promise = new Promise((
|
|
1454
|
+
const promise = new Promise((resolve2) => {
|
|
830
1455
|
timeout = setTimeout(() => {
|
|
831
1456
|
cleanup?.();
|
|
832
|
-
|
|
1457
|
+
resolve2(null);
|
|
833
1458
|
}, 5e3);
|
|
834
1459
|
cleanup = ctx.hooks.hookOnce(RUNTIME_PAGE_RECONNECTED_EVENT, (payload) => {
|
|
835
1460
|
if (timeout) {
|
|
836
1461
|
clearTimeout(timeout);
|
|
837
1462
|
}
|
|
838
|
-
|
|
1463
|
+
resolve2(isPageTarget(payload) ? payload : null);
|
|
839
1464
|
});
|
|
840
1465
|
});
|
|
841
1466
|
return {
|
|
@@ -919,7 +1544,7 @@ function getPathname(url) {
|
|
|
919
1544
|
}
|
|
920
1545
|
|
|
921
1546
|
// src/mcp/tools/screenshot.ts
|
|
922
|
-
var
|
|
1547
|
+
var import_zod7 = require("zod");
|
|
923
1548
|
|
|
924
1549
|
// src/cdp/cdpScreenshot.ts
|
|
925
1550
|
async function cdpCaptureScreenshot(options) {
|
|
@@ -1025,16 +1650,16 @@ function isElementRect(value) {
|
|
|
1025
1650
|
|
|
1026
1651
|
// src/mcp/tools/screenshotOutput.ts
|
|
1027
1652
|
var import_node_crypto = require("crypto");
|
|
1028
|
-
var
|
|
1029
|
-
var
|
|
1653
|
+
var import_promises2 = require("fs/promises");
|
|
1654
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
1030
1655
|
async function createScreenshotOutput(ctx, payload) {
|
|
1031
1656
|
if (ctx.options.screenshot.type === "base64") {
|
|
1032
1657
|
return payload;
|
|
1033
1658
|
}
|
|
1034
1659
|
const saveDir = resolveScreenshotSaveDir(ctx);
|
|
1035
|
-
await (0,
|
|
1036
|
-
const filePath =
|
|
1037
|
-
await (0,
|
|
1660
|
+
await (0, import_promises2.mkdir)(saveDir, { recursive: true });
|
|
1661
|
+
const filePath = import_node_path3.default.join(saveDir, createScreenshotFileName(payload));
|
|
1662
|
+
await (0, import_promises2.writeFile)(filePath, Buffer.from(payload.data, "base64"));
|
|
1038
1663
|
return {
|
|
1039
1664
|
source: payload.source,
|
|
1040
1665
|
target: payload.target,
|
|
@@ -1057,10 +1682,10 @@ function resolveScreenshotSaveDir(ctx) {
|
|
|
1057
1682
|
if (!root) {
|
|
1058
1683
|
throw new Error("Vite server root is required for screenshot path output");
|
|
1059
1684
|
}
|
|
1060
|
-
if (
|
|
1685
|
+
if (import_node_path3.default.isAbsolute(saveDir)) {
|
|
1061
1686
|
return saveDir;
|
|
1062
1687
|
}
|
|
1063
|
-
return
|
|
1688
|
+
return import_node_path3.default.resolve(root, saveDir);
|
|
1064
1689
|
}
|
|
1065
1690
|
function createScreenshotFileName(payload) {
|
|
1066
1691
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -1072,21 +1697,21 @@ function createProjectRelativePath(ctx, filePath) {
|
|
|
1072
1697
|
if (!root) {
|
|
1073
1698
|
throw new Error("Vite server root is required for screenshot path output");
|
|
1074
1699
|
}
|
|
1075
|
-
return
|
|
1700
|
+
return import_node_path3.default.relative(root, filePath).split(import_node_path3.default.sep).join("/");
|
|
1076
1701
|
}
|
|
1077
1702
|
|
|
1078
1703
|
// src/mcp/tools/screenshot.ts
|
|
1079
1704
|
var DEFAULT_SCREENSHOT_TARGET = "viewport";
|
|
1080
1705
|
var DEFAULT_SCREENSHOT_FORMAT = "png";
|
|
1081
1706
|
var screenshotInputSchema = {
|
|
1082
|
-
pageId:
|
|
1083
|
-
target:
|
|
1084
|
-
selector:
|
|
1085
|
-
format:
|
|
1086
|
-
prefer:
|
|
1087
|
-
quality:
|
|
1088
|
-
scale:
|
|
1089
|
-
snapdom:
|
|
1707
|
+
pageId: import_zod7.z.string().optional(),
|
|
1708
|
+
target: import_zod7.z.enum(["viewport", "fullPage", "element"]).optional(),
|
|
1709
|
+
selector: import_zod7.z.string().optional(),
|
|
1710
|
+
format: import_zod7.z.enum(["png", "jpeg", "webp"]).optional(),
|
|
1711
|
+
prefer: import_zod7.z.enum(["auto", "cdp", "runtime"]).optional(),
|
|
1712
|
+
quality: import_zod7.z.number().optional(),
|
|
1713
|
+
scale: import_zod7.z.number().optional(),
|
|
1714
|
+
snapdom: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).optional()
|
|
1090
1715
|
};
|
|
1091
1716
|
function registerScreenshotTools(server, ctx) {
|
|
1092
1717
|
server.registerTool(
|
|
@@ -1159,7 +1784,7 @@ async function createRuntimeScreenshot(ctx, input, normalized) {
|
|
|
1159
1784
|
`screenshot is too large: ${String(result.byteLength)} bytes`
|
|
1160
1785
|
);
|
|
1161
1786
|
}
|
|
1162
|
-
if (!
|
|
1787
|
+
if (!isPlainRecord2(result)) {
|
|
1163
1788
|
return createToolError("runtime screenshot returned an invalid response");
|
|
1164
1789
|
}
|
|
1165
1790
|
if (result.ok === false) {
|
|
@@ -1188,9 +1813,9 @@ async function createScreenshotResponse(ctx, result) {
|
|
|
1188
1813
|
}
|
|
1189
1814
|
}
|
|
1190
1815
|
function isScreenshotTooLarge(ctx, result) {
|
|
1191
|
-
return
|
|
1816
|
+
return isPlainRecord2(result) && "byteLength" in result && typeof result.byteLength === "number" && result.byteLength > ctx.options.screenshot.maxBytes;
|
|
1192
1817
|
}
|
|
1193
|
-
function
|
|
1818
|
+
function isPlainRecord2(value) {
|
|
1194
1819
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1195
1820
|
}
|
|
1196
1821
|
function createMimeType(format) {
|
|
@@ -1205,8 +1830,8 @@ function isScreenshotImagePayload(result) {
|
|
|
1205
1830
|
}
|
|
1206
1831
|
|
|
1207
1832
|
// src/mcp/tools/vue.ts
|
|
1208
|
-
var
|
|
1209
|
-
var
|
|
1833
|
+
var import_nanoid3 = require("nanoid");
|
|
1834
|
+
var import_zod8 = require("zod");
|
|
1210
1835
|
function registerVueTools(server, ctx) {
|
|
1211
1836
|
server.registerTool(
|
|
1212
1837
|
MCP_TOOL_NAMES.getComponentTree,
|
|
@@ -1219,7 +1844,7 @@ function registerVueTools(server, ctx) {
|
|
|
1219
1844
|
MCP_TOOL_NAMES.getComponentState,
|
|
1220
1845
|
{
|
|
1221
1846
|
description: "Get Vue component state.",
|
|
1222
|
-
inputSchema: { componentName:
|
|
1847
|
+
inputSchema: { componentName: import_zod8.z.string() }
|
|
1223
1848
|
},
|
|
1224
1849
|
async ({ componentName }) => requestVueData(ctx, (event) => {
|
|
1225
1850
|
void ctx.rpcServer?.getInspectorState({ event, componentName });
|
|
@@ -1230,10 +1855,10 @@ function registerVueTools(server, ctx) {
|
|
|
1230
1855
|
{
|
|
1231
1856
|
description: "Edit Vue component state.",
|
|
1232
1857
|
inputSchema: {
|
|
1233
|
-
componentName:
|
|
1234
|
-
path:
|
|
1235
|
-
value:
|
|
1236
|
-
valueType:
|
|
1858
|
+
componentName: import_zod8.z.string(),
|
|
1859
|
+
path: import_zod8.z.array(import_zod8.z.string()),
|
|
1860
|
+
value: import_zod8.z.string(),
|
|
1861
|
+
valueType: import_zod8.z.enum(["string", "number", "boolean", "object", "array"])
|
|
1237
1862
|
}
|
|
1238
1863
|
},
|
|
1239
1864
|
({ componentName, path: path8, value, valueType }) => {
|
|
@@ -1253,7 +1878,7 @@ function registerVueTools(server, ctx) {
|
|
|
1253
1878
|
MCP_TOOL_NAMES.highlightComponent,
|
|
1254
1879
|
{
|
|
1255
1880
|
description: "Highlight a Vue component.",
|
|
1256
|
-
inputSchema: { componentName:
|
|
1881
|
+
inputSchema: { componentName: import_zod8.z.string() }
|
|
1257
1882
|
},
|
|
1258
1883
|
({ componentName }) => {
|
|
1259
1884
|
if (!ctx.rpcServer) {
|
|
@@ -1281,7 +1906,7 @@ function registerVueTools(server, ctx) {
|
|
|
1281
1906
|
MCP_TOOL_NAMES.getPiniaState,
|
|
1282
1907
|
{
|
|
1283
1908
|
description: "Get Pinia store state.",
|
|
1284
|
-
inputSchema: { storeName:
|
|
1909
|
+
inputSchema: { storeName: import_zod8.z.string() }
|
|
1285
1910
|
},
|
|
1286
1911
|
async ({ storeName }) => requestVueData(ctx, (event) => {
|
|
1287
1912
|
void ctx.rpcServer?.getPiniaState({ event, storeName });
|
|
@@ -1292,7 +1917,7 @@ async function requestVueData(ctx, trigger) {
|
|
|
1292
1917
|
if (!ctx.rpcServer) {
|
|
1293
1918
|
return vueBridgeUnavailable();
|
|
1294
1919
|
}
|
|
1295
|
-
const event = (0,
|
|
1920
|
+
const event = (0, import_nanoid3.nanoid)();
|
|
1296
1921
|
const data = await waitForVueHook(ctx, event, () => {
|
|
1297
1922
|
trigger(event);
|
|
1298
1923
|
});
|
|
@@ -1301,13 +1926,13 @@ async function requestVueData(ctx, trigger) {
|
|
|
1301
1926
|
};
|
|
1302
1927
|
}
|
|
1303
1928
|
function waitForVueHook(ctx, event, trigger) {
|
|
1304
|
-
return new Promise((
|
|
1929
|
+
return new Promise((resolve2) => {
|
|
1305
1930
|
const timeout = setTimeout(() => {
|
|
1306
|
-
|
|
1931
|
+
resolve2({ ok: false, error: "Vue runtime bridge response timed out" });
|
|
1307
1932
|
}, 5e3);
|
|
1308
1933
|
ctx.hooks.hookOnce(event, (data) => {
|
|
1309
1934
|
clearTimeout(timeout);
|
|
1310
|
-
|
|
1935
|
+
resolve2(data);
|
|
1311
1936
|
});
|
|
1312
1937
|
trigger();
|
|
1313
1938
|
});
|
|
@@ -1328,6 +1953,7 @@ function createMcpServer(ctx, vite) {
|
|
|
1328
1953
|
registerConsoleTools(server, ctx);
|
|
1329
1954
|
registerEvaluateTools(server, ctx);
|
|
1330
1955
|
registerNetworkTools(server, ctx);
|
|
1956
|
+
registerPerformanceTools(server, ctx);
|
|
1331
1957
|
registerVueTools(server, ctx);
|
|
1332
1958
|
return server;
|
|
1333
1959
|
}
|
|
@@ -1415,6 +2041,18 @@ function createServerVueRuntimeRpc(ctx) {
|
|
|
1415
2041
|
onScreenshotTaken: (event, data) => {
|
|
1416
2042
|
void ctx.hooks.callHook(event, data);
|
|
1417
2043
|
},
|
|
2044
|
+
recordPerformance: () => void 0,
|
|
2045
|
+
onPerformanceRecorded: (event, data) => {
|
|
2046
|
+
void ctx.hooks.callHook(event, data);
|
|
2047
|
+
},
|
|
2048
|
+
startPerformanceRecording: () => void 0,
|
|
2049
|
+
onPerformanceRecordingStarted: (event, data) => {
|
|
2050
|
+
void ctx.hooks.callHook(event, data);
|
|
2051
|
+
},
|
|
2052
|
+
stopPerformanceRecording: () => void 0,
|
|
2053
|
+
onPerformanceRecordingStopped: (event, data) => {
|
|
2054
|
+
void ctx.hooks.callHook(event, data);
|
|
2055
|
+
},
|
|
1418
2056
|
getInspectorTree: () => void 0,
|
|
1419
2057
|
onInspectorTreeUpdated: (event, data) => {
|
|
1420
2058
|
void ctx.hooks.callHook(event, data);
|
|
@@ -1441,7 +2079,7 @@ function createServerVueRuntimeRpc(ctx) {
|
|
|
1441
2079
|
}
|
|
1442
2080
|
|
|
1443
2081
|
// src/cdp/cdpConsole.ts
|
|
1444
|
-
var
|
|
2082
|
+
var import_nanoid4 = require("nanoid");
|
|
1445
2083
|
|
|
1446
2084
|
// src/shared/serialization.ts
|
|
1447
2085
|
function safeStringify(value) {
|
|
@@ -1470,7 +2108,7 @@ async function startCdpConsole(options) {
|
|
|
1470
2108
|
await options.client.Runtime.enable();
|
|
1471
2109
|
options.client.Runtime.consoleAPICalled((event) => {
|
|
1472
2110
|
options.push({
|
|
1473
|
-
id: (0,
|
|
2111
|
+
id: (0, import_nanoid4.nanoid)(),
|
|
1474
2112
|
pageId: options.pageId,
|
|
1475
2113
|
source: "cdp",
|
|
1476
2114
|
level: normalizeConsoleLevel(event.type),
|
|
@@ -1490,7 +2128,7 @@ function normalizeConsoleLevel(level) {
|
|
|
1490
2128
|
}
|
|
1491
2129
|
|
|
1492
2130
|
// src/cdp/cdpNetwork.ts
|
|
1493
|
-
var
|
|
2131
|
+
var import_nanoid5 = require("nanoid");
|
|
1494
2132
|
|
|
1495
2133
|
// src/shared/sanitize.ts
|
|
1496
2134
|
function maskHeaders(headers = {}, maskNames = []) {
|
|
@@ -1530,7 +2168,7 @@ async function startCdpNetwork(options) {
|
|
|
1530
2168
|
await options.client.Network.enable();
|
|
1531
2169
|
options.client.Network.requestWillBeSent((event) => {
|
|
1532
2170
|
records.set(event.requestId, {
|
|
1533
|
-
id: (0,
|
|
2171
|
+
id: (0, import_nanoid5.nanoid)(),
|
|
1534
2172
|
pageId: options.pageId,
|
|
1535
2173
|
source: "cdp",
|
|
1536
2174
|
url: event.request.url,
|
|
@@ -1701,7 +2339,7 @@ async function startCdpObservers(ctx, target, client) {
|
|
|
1701
2339
|
|
|
1702
2340
|
// src/plugin/injectRuntime.ts
|
|
1703
2341
|
var import_node_module = require("module");
|
|
1704
|
-
var
|
|
2342
|
+
var import_node_path4 = require("path");
|
|
1705
2343
|
function createRuntimeInjectionController(options, getConfig) {
|
|
1706
2344
|
return {
|
|
1707
2345
|
resolveId(importee) {
|
|
@@ -1785,7 +2423,7 @@ function createSnapdomLoaderModule(root) {
|
|
|
1785
2423
|
}
|
|
1786
2424
|
function canResolveSnapdomFromProject(root) {
|
|
1787
2425
|
try {
|
|
1788
|
-
(0, import_node_module.createRequire)((0,
|
|
2426
|
+
(0, import_node_module.createRequire)((0, import_node_path4.join)(root ?? process.cwd(), "package.json")).resolve(
|
|
1789
2427
|
"@zumer/snapdom"
|
|
1790
2428
|
);
|
|
1791
2429
|
return true;
|
|
@@ -1824,18 +2462,18 @@ function getPluginPath(plugin) {
|
|
|
1824
2462
|
}
|
|
1825
2463
|
|
|
1826
2464
|
// src/plugin/mcpClientConfig/index.ts
|
|
1827
|
-
var
|
|
1828
|
-
var
|
|
2465
|
+
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
2466
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
1829
2467
|
|
|
1830
2468
|
// src/plugin/mcpClientConfig/codexConfig.ts
|
|
1831
|
-
var
|
|
1832
|
-
var
|
|
2469
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
2470
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1833
2471
|
async function updateCodexMcpClientConfig(options) {
|
|
1834
2472
|
try {
|
|
1835
2473
|
const current = await readOptionalTextFile(options.configPath);
|
|
1836
2474
|
const next = replaceOrAppendOwnedBlock(current, options);
|
|
1837
|
-
await
|
|
1838
|
-
await
|
|
2475
|
+
await import_promises3.default.mkdir(import_node_path5.default.dirname(options.configPath), { recursive: true });
|
|
2476
|
+
await import_promises3.default.writeFile(options.configPath, next);
|
|
1839
2477
|
} catch (error) {
|
|
1840
2478
|
console.warn(
|
|
1841
2479
|
`[vite-plugin-vue-mcp-next] Failed to update Codex MCP config at ${options.configPath}: ${formatError(error)}`
|
|
@@ -1907,7 +2545,7 @@ function renameServerTableHeader(line, fromServerName, toServerName) {
|
|
|
1907
2545
|
}
|
|
1908
2546
|
async function readOptionalTextFile(filePath) {
|
|
1909
2547
|
try {
|
|
1910
|
-
return await
|
|
2548
|
+
return await import_promises3.default.readFile(filePath, "utf-8");
|
|
1911
2549
|
} catch (error) {
|
|
1912
2550
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1913
2551
|
return "";
|
|
@@ -1933,16 +2571,16 @@ function isNodeError(error) {
|
|
|
1933
2571
|
}
|
|
1934
2572
|
|
|
1935
2573
|
// src/plugin/mcpClientConfig/jsonConfig.ts
|
|
1936
|
-
var
|
|
1937
|
-
var
|
|
2574
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
2575
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1938
2576
|
async function updateJsonMcpClientConfig(options) {
|
|
1939
2577
|
try {
|
|
1940
2578
|
const config = await readJsonConfig(options.configPath);
|
|
1941
|
-
if (!
|
|
2579
|
+
if (!isPlainRecord3(config)) {
|
|
1942
2580
|
warnConfigFailure(options, "config root must be a JSON object");
|
|
1943
2581
|
return;
|
|
1944
2582
|
}
|
|
1945
|
-
const mcpServers =
|
|
2583
|
+
const mcpServers = isPlainRecord3(config.mcpServers) ? config.mcpServers : {};
|
|
1946
2584
|
if (Object.hasOwn(mcpServers, options.serverName)) {
|
|
1947
2585
|
return;
|
|
1948
2586
|
}
|
|
@@ -1974,8 +2612,8 @@ function renameLegacyServer(mcpServers, options) {
|
|
|
1974
2612
|
);
|
|
1975
2613
|
}
|
|
1976
2614
|
async function writeJsonConfig(configPath, config) {
|
|
1977
|
-
await
|
|
1978
|
-
await
|
|
2615
|
+
await import_promises4.default.mkdir(import_node_path6.default.dirname(configPath), { recursive: true });
|
|
2616
|
+
await import_promises4.default.writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
1979
2617
|
`);
|
|
1980
2618
|
}
|
|
1981
2619
|
async function readJsonConfig(configPath) {
|
|
@@ -1987,7 +2625,7 @@ async function readJsonConfig(configPath) {
|
|
|
1987
2625
|
}
|
|
1988
2626
|
async function readOptionalTextFile2(filePath) {
|
|
1989
2627
|
try {
|
|
1990
|
-
return await
|
|
2628
|
+
return await import_promises4.default.readFile(filePath, "utf-8");
|
|
1991
2629
|
} catch (error) {
|
|
1992
2630
|
if (isNodeError2(error) && error.code === "ENOENT") {
|
|
1993
2631
|
return "{}";
|
|
@@ -1995,7 +2633,7 @@ async function readOptionalTextFile2(filePath) {
|
|
|
1995
2633
|
throw error;
|
|
1996
2634
|
}
|
|
1997
2635
|
}
|
|
1998
|
-
function
|
|
2636
|
+
function isPlainRecord3(value) {
|
|
1999
2637
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2000
2638
|
}
|
|
2001
2639
|
function warnConfigFailure(options, reason) {
|
|
@@ -2019,12 +2657,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
|
|
|
2019
2657
|
root,
|
|
2020
2658
|
clientName: "cursor",
|
|
2021
2659
|
enabled: options.cursor,
|
|
2022
|
-
entryPath:
|
|
2660
|
+
entryPath: import_node_path7.default.join(root, ".cursor"),
|
|
2023
2661
|
entryKind: "directory",
|
|
2024
2662
|
userOptions,
|
|
2025
2663
|
createJob: () => updateJsonMcpClientConfig({
|
|
2026
2664
|
clientName: "Cursor",
|
|
2027
|
-
configPath:
|
|
2665
|
+
configPath: import_node_path7.default.join(root, ".cursor", "mcp.json"),
|
|
2028
2666
|
mcpUrl: sseUrl,
|
|
2029
2667
|
serverName,
|
|
2030
2668
|
legacyServerNames
|
|
@@ -2034,11 +2672,11 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
|
|
|
2034
2672
|
root,
|
|
2035
2673
|
clientName: "codex",
|
|
2036
2674
|
enabled: options.codex,
|
|
2037
|
-
entryPath:
|
|
2675
|
+
entryPath: import_node_path7.default.join(root, ".codex"),
|
|
2038
2676
|
entryKind: "directory",
|
|
2039
2677
|
userOptions,
|
|
2040
2678
|
createJob: () => updateCodexMcpClientConfig({
|
|
2041
|
-
configPath:
|
|
2679
|
+
configPath: import_node_path7.default.join(root, ".codex", "config.toml"),
|
|
2042
2680
|
mcpUrl: streamableHttpUrl,
|
|
2043
2681
|
serverName,
|
|
2044
2682
|
legacyServerNames
|
|
@@ -2048,12 +2686,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
|
|
|
2048
2686
|
root,
|
|
2049
2687
|
clientName: "claudeCode",
|
|
2050
2688
|
enabled: options.claudeCode,
|
|
2051
|
-
entryPath:
|
|
2689
|
+
entryPath: import_node_path7.default.join(root, ".mcp.json"),
|
|
2052
2690
|
entryKind: "file",
|
|
2053
2691
|
userOptions,
|
|
2054
2692
|
createJob: () => updateJsonMcpClientConfig({
|
|
2055
2693
|
clientName: "Claude Code",
|
|
2056
|
-
configPath:
|
|
2694
|
+
configPath: import_node_path7.default.join(root, ".mcp.json"),
|
|
2057
2695
|
mcpUrl: sseUrl,
|
|
2058
2696
|
serverName,
|
|
2059
2697
|
legacyServerNames
|
|
@@ -2063,12 +2701,12 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options,
|
|
|
2063
2701
|
root,
|
|
2064
2702
|
clientName: "trae",
|
|
2065
2703
|
enabled: options.trae,
|
|
2066
|
-
entryPath:
|
|
2704
|
+
entryPath: import_node_path7.default.join(root, ".trae"),
|
|
2067
2705
|
entryKind: "directory",
|
|
2068
2706
|
userOptions,
|
|
2069
2707
|
createJob: () => updateJsonMcpClientConfig({
|
|
2070
2708
|
clientName: "Trae",
|
|
2071
|
-
configPath:
|
|
2709
|
+
configPath: import_node_path7.default.join(root, ".trae", "mcp.json"),
|
|
2072
2710
|
mcpUrl: sseUrl,
|
|
2073
2711
|
serverName,
|
|
2074
2712
|
legacyServerNames
|
|
@@ -2107,7 +2745,7 @@ function isClientExplicitlyConfigured(clientName, userOptions) {
|
|
|
2107
2745
|
}
|
|
2108
2746
|
async function hasExpectedEntry(entryPath, entryKind) {
|
|
2109
2747
|
try {
|
|
2110
|
-
const stat = await
|
|
2748
|
+
const stat = await import_promises5.default.stat(entryPath);
|
|
2111
2749
|
return entryKind === "directory" ? stat.isDirectory() : stat.isFile();
|
|
2112
2750
|
} catch (error) {
|
|
2113
2751
|
if (isNodeError3(error) && error.code === "ENOENT") {
|
|
@@ -2127,12 +2765,12 @@ function isNodeError3(error) {
|
|
|
2127
2765
|
}
|
|
2128
2766
|
|
|
2129
2767
|
// src/plugin/skillConfig/index.ts
|
|
2130
|
-
var
|
|
2131
|
-
var
|
|
2768
|
+
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
2769
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
2132
2770
|
|
|
2133
2771
|
// src/plugin/skillConfig/writers.ts
|
|
2134
|
-
var
|
|
2135
|
-
var
|
|
2772
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
2773
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
2136
2774
|
var GENERATED_SKILL_CONFIG_MARKER = "<!-- Generated by vite-plugin-vue-mcp-next. Safe to edit, but automatic updates only apply while this marker remains. -->";
|
|
2137
2775
|
async function writeGeneratedTextFile(options) {
|
|
2138
2776
|
try {
|
|
@@ -2143,8 +2781,8 @@ async function writeGeneratedTextFile(options) {
|
|
|
2143
2781
|
);
|
|
2144
2782
|
return;
|
|
2145
2783
|
}
|
|
2146
|
-
await
|
|
2147
|
-
await
|
|
2784
|
+
await import_promises6.default.mkdir(import_node_path8.default.dirname(options.filePath), { recursive: true });
|
|
2785
|
+
await import_promises6.default.writeFile(options.filePath, options.content);
|
|
2148
2786
|
} catch (error) {
|
|
2149
2787
|
console.warn(
|
|
2150
2788
|
`[vite-plugin-vue-mcp-next] Failed to update ${options.targetName} at ${options.filePath}: ${formatError4(error)}`
|
|
@@ -2153,7 +2791,7 @@ async function writeGeneratedTextFile(options) {
|
|
|
2153
2791
|
}
|
|
2154
2792
|
async function readOptionalTextFile3(filePath) {
|
|
2155
2793
|
try {
|
|
2156
|
-
return await
|
|
2794
|
+
return await import_promises6.default.readFile(filePath, "utf-8");
|
|
2157
2795
|
} catch (error) {
|
|
2158
2796
|
if (isNodeError4(error) && error.code === "ENOENT") {
|
|
2159
2797
|
return "";
|
|
@@ -2170,7 +2808,7 @@ function isNodeError4(error) {
|
|
|
2170
2808
|
|
|
2171
2809
|
// src/plugin/skillConfig/index.ts
|
|
2172
2810
|
var PACKAGE_NAME = "@xiaou66/vite-plugin-vue-mcp-next";
|
|
2173
|
-
var PACKAGED_SKILL_PATH =
|
|
2811
|
+
var PACKAGED_SKILL_PATH = import_node_path9.default.join("skills", "vite-mcp-next", "SKILL.md");
|
|
2174
2812
|
async function updateSkillConfigs(root, options) {
|
|
2175
2813
|
if (!options.autoConfig) {
|
|
2176
2814
|
return;
|
|
@@ -2186,13 +2824,13 @@ async function updateSkillConfigs(root, options) {
|
|
|
2186
2824
|
function createSkillConfigDescriptors(root) {
|
|
2187
2825
|
return [
|
|
2188
2826
|
{
|
|
2189
|
-
entryPath:
|
|
2190
|
-
filePath:
|
|
2827
|
+
entryPath: import_node_path9.default.join(root, ".codex"),
|
|
2828
|
+
filePath: import_node_path9.default.join(root, ".codex", "skills", "vite-mcp-next", "SKILL.md"),
|
|
2191
2829
|
targetName: "Codex skill"
|
|
2192
2830
|
},
|
|
2193
2831
|
{
|
|
2194
|
-
entryPath:
|
|
2195
|
-
filePath:
|
|
2832
|
+
entryPath: import_node_path9.default.join(root, ".claude"),
|
|
2833
|
+
filePath: import_node_path9.default.join(
|
|
2196
2834
|
root,
|
|
2197
2835
|
".claude",
|
|
2198
2836
|
"skills",
|
|
@@ -2202,8 +2840,8 @@ function createSkillConfigDescriptors(root) {
|
|
|
2202
2840
|
targetName: "Claude Code skill"
|
|
2203
2841
|
},
|
|
2204
2842
|
{
|
|
2205
|
-
entryPath:
|
|
2206
|
-
filePath:
|
|
2843
|
+
entryPath: import_node_path9.default.join(root, ".cursor"),
|
|
2844
|
+
filePath: import_node_path9.default.join(root, ".cursor", "rules", "vite-mcp-next.mdc"),
|
|
2207
2845
|
targetName: "Cursor rule"
|
|
2208
2846
|
}
|
|
2209
2847
|
];
|
|
@@ -2227,7 +2865,7 @@ async function readPackagedSkillContent(root) {
|
|
|
2227
2865
|
const candidates = getPackagedSkillCandidates(root);
|
|
2228
2866
|
for (const candidate of candidates) {
|
|
2229
2867
|
try {
|
|
2230
|
-
return await
|
|
2868
|
+
return await import_promises7.default.readFile(candidate, "utf-8");
|
|
2231
2869
|
} catch (error) {
|
|
2232
2870
|
if (isNodeError5(error) && error.code === "ENOENT") {
|
|
2233
2871
|
continue;
|
|
@@ -2251,14 +2889,14 @@ async function safelyReadPackagedSkillContent(root) {
|
|
|
2251
2889
|
}
|
|
2252
2890
|
function getPackagedSkillCandidates(root) {
|
|
2253
2891
|
return [
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2892
|
+
import_node_path9.default.resolve(root, "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
|
|
2893
|
+
import_node_path9.default.resolve(process.cwd(), "node_modules", PACKAGE_NAME, PACKAGED_SKILL_PATH),
|
|
2894
|
+
import_node_path9.default.resolve(process.cwd(), PACKAGED_SKILL_PATH)
|
|
2257
2895
|
];
|
|
2258
2896
|
}
|
|
2259
2897
|
async function hasDirectoryEntry(entryPath) {
|
|
2260
2898
|
try {
|
|
2261
|
-
const stat = await
|
|
2899
|
+
const stat = await import_promises7.default.stat(entryPath);
|
|
2262
2900
|
return stat.isDirectory();
|
|
2263
2901
|
} catch (error) {
|
|
2264
2902
|
if (isNodeError5(error) && error.code === "ENOENT") {
|
|
@@ -2337,6 +2975,14 @@ function vueMcpNext(userOptions = {}) {
|
|
|
2337
2975
|
}
|
|
2338
2976
|
}
|
|
2339
2977
|
);
|
|
2978
|
+
server.ws.on(
|
|
2979
|
+
"vite-plugin-vue-mcp-next:performance-record",
|
|
2980
|
+
(payload) => {
|
|
2981
|
+
if (isPerformanceReport2(payload)) {
|
|
2982
|
+
appendPerformanceReport(ctx, payload);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
);
|
|
2340
2986
|
const port = String(server.config.server.port || 5173);
|
|
2341
2987
|
const mcpSseUrl = `http://${options.host}:${port}${options.mcpPath}/sse`;
|
|
2342
2988
|
const mcpStreamableHttpUrl = `http://${options.host}:${port}${options.mcpPath}/mcp`;
|
|
@@ -2399,6 +3045,13 @@ function isNetworkRecord(payload) {
|
|
|
2399
3045
|
const record = payload;
|
|
2400
3046
|
return typeof record.id === "string" && typeof record.pageId === "string" && record.source === "hook" && typeof record.url === "string" && typeof record.method === "string" && typeof record.startedAt === "number";
|
|
2401
3047
|
}
|
|
3048
|
+
function isPerformanceReport2(payload) {
|
|
3049
|
+
if (!payload || typeof payload !== "object") {
|
|
3050
|
+
return false;
|
|
3051
|
+
}
|
|
3052
|
+
const report = payload;
|
|
3053
|
+
return typeof report.recordingId === "string" && typeof report.pageId === "string" && (report.source === "hook" || report.source === "cdp") && Boolean(report.summary) && Array.isArray(report.longTasks) && Array.isArray(report.limitations);
|
|
3054
|
+
}
|
|
2402
3055
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2403
3056
|
0 && (module.exports = {
|
|
2404
3057
|
vueMcpNext
|