180 lines
6.9 KiB
JavaScript
180 lines
6.9 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
0 && (module.exports = {
|
|
handlePageMetadataResponse: null,
|
|
registerGetPageMetadataTool: null
|
|
});
|
|
function _export(target, all) {
|
|
for(var name in all)Object.defineProperty(target, name, {
|
|
enumerable: true,
|
|
get: all[name]
|
|
});
|
|
}
|
|
_export(exports, {
|
|
handlePageMetadataResponse: function() {
|
|
return handlePageMetadataResponse;
|
|
},
|
|
registerGetPageMetadataTool: function() {
|
|
return registerGetPageMetadataTool;
|
|
}
|
|
});
|
|
const _hotreloadertypes = require("../../dev/hot-reloader-types");
|
|
const _browsercommunication = require("./utils/browser-communication");
|
|
const _mcptelemetrytracker = require("../mcp-telemetry-tracker");
|
|
function registerGetPageMetadataTool(server, sendHmrMessage, getActiveConnectionCount) {
|
|
server.registerTool('get_page_metadata', {
|
|
description: 'Get runtime metadata about what contributes to the current page render from active browser sessions.',
|
|
inputSchema: {}
|
|
}, async (_request)=>{
|
|
// Track telemetry
|
|
_mcptelemetrytracker.mcpTelemetryTracker.recordToolCall('mcp/get_page_metadata');
|
|
try {
|
|
const connectionCount = getActiveConnectionCount();
|
|
if (connectionCount === 0) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: 'No browser sessions connected. Please open your application in a browser to retrieve page metadata.'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
const responses = await (0, _browsercommunication.createBrowserRequest)(_hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.REQUEST_PAGE_METADATA, sendHmrMessage, getActiveConnectionCount, _browsercommunication.DEFAULT_BROWSER_REQUEST_TIMEOUT_MS);
|
|
if (responses.length === 0) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: 'No browser sessions responded.'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
const sessionMetadata = [];
|
|
for (const response of responses){
|
|
if (response.data) {
|
|
// TODO: Add other metadata for the current page render here. Currently, we only have segment trie data.
|
|
const pageMetadata = convertSegmentTrieToPageMetadata(response.data);
|
|
sessionMetadata.push({
|
|
url: response.url,
|
|
metadata: pageMetadata
|
|
});
|
|
}
|
|
}
|
|
if (sessionMetadata.length === 0) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `No page metadata available from ${responses.length} browser session(s).`
|
|
}
|
|
]
|
|
};
|
|
}
|
|
const output = formatPageMetadata(sessionMetadata);
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: output
|
|
}
|
|
]
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
}
|
|
]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
function handlePageMetadataResponse(requestId, segmentTrieData, url) {
|
|
(0, _browsercommunication.handleBrowserPageResponse)(requestId, segmentTrieData, url || '');
|
|
}
|
|
function convertSegmentTrieToPageMetadata(data) {
|
|
const segments = [];
|
|
if (data.segmentTrie) {
|
|
// Traverse the trie and collect all segments
|
|
function traverseTrie(node) {
|
|
if (node.value) {
|
|
segments.push({
|
|
type: node.value.type,
|
|
pagePath: node.value.pagePath,
|
|
boundaryType: node.value.boundaryType
|
|
});
|
|
}
|
|
for (const childNode of Object.values(node.children)){
|
|
if (childNode) {
|
|
traverseTrie(childNode);
|
|
}
|
|
}
|
|
}
|
|
traverseTrie(data.segmentTrie);
|
|
}
|
|
return {
|
|
segments,
|
|
routerType: data.routerType
|
|
};
|
|
}
|
|
function formatPageMetadata(sessionMetadata) {
|
|
let output = `# Page metadata from ${sessionMetadata.length} browser session(s)\n\n`;
|
|
for (const { url, metadata } of sessionMetadata){
|
|
let displayUrl = url;
|
|
try {
|
|
const urlObj = new URL(url);
|
|
displayUrl = urlObj.pathname + urlObj.search + urlObj.hash;
|
|
} catch {
|
|
// If URL parsing fails, use the original URL
|
|
}
|
|
output += `## Session: ${displayUrl}\n\n`;
|
|
output += `**Router type:** ${metadata.routerType}\n\n`;
|
|
if (metadata.segments.length === 0) {
|
|
output += '*No segments found*\n\n';
|
|
} else {
|
|
output += '### Files powering this page:\n\n';
|
|
// Ensure consistent output to avoid flaky tests
|
|
const sortedSegments = [
|
|
...metadata.segments
|
|
].sort((a, b)=>{
|
|
const typeOrder = (segment)=>{
|
|
const type = segment.boundaryType || segment.type;
|
|
if (type === 'layout') return 0;
|
|
if (type.startsWith('boundary:')) return 1;
|
|
if (type === 'page') return 2;
|
|
return 3;
|
|
};
|
|
const aOrder = typeOrder(a);
|
|
const bOrder = typeOrder(b);
|
|
if (aOrder !== bOrder) return aOrder - bOrder;
|
|
return a.pagePath.localeCompare(b.pagePath);
|
|
});
|
|
for (const segment of sortedSegments){
|
|
const path = segment.pagePath;
|
|
const isBuiltin = path.startsWith('__next_builtin__');
|
|
const type = segment.boundaryType || segment.type;
|
|
const isBoundary = type.startsWith('boundary:');
|
|
let displayPath = path.replace(/@boundary$/, '').replace(/^__next_builtin__/, '');
|
|
if (!isBuiltin && !displayPath.startsWith('app/')) {
|
|
displayPath = `app/${displayPath}`;
|
|
}
|
|
const descriptors = [];
|
|
if (isBoundary) descriptors.push('boundary');
|
|
if (isBuiltin) descriptors.push('builtin');
|
|
const descriptor = descriptors.length > 0 ? ` (${descriptors.join(', ')})` : '';
|
|
output += `- ${displayPath}${descriptor}\n`;
|
|
}
|
|
output += '\n';
|
|
}
|
|
output += '---\n\n';
|
|
}
|
|
return output.trim();
|
|
}
|
|
|
|
//# sourceMappingURL=get-page-metadata.js.map
|