33 * Copyright 2025 Google LLC
44 * SPDX-License-Identifier: Apache-2.0
55 */
6+ import {
7+ AggregatedIssue ,
8+ Marked ,
9+ findTitleFromMarkdownAst ,
10+ } from '../node_modules/chrome-devtools-frontend/mcp/mcp.js' ;
11+
612import type { ConsoleMessageData } from './formatters/consoleFormatter.js' ;
713import {
814 formatConsoleEventShort ,
@@ -16,6 +22,8 @@ import {
1622 getStatusFromRequest ,
1723} from './formatters/networkFormatter.js' ;
1824import { formatSnapshotNode } from './formatters/snapshotFormatter.js' ;
25+ import { getIssueDescription } from './issue-descriptions.js' ;
26+ import { logger } from './logger.js' ;
1927import type { McpContext } from './McpContext.js' ;
2028import type {
2129 ConsoleMessage ,
@@ -269,40 +277,70 @@ export class McpResponse implements Response {
269277 if ( 'type' in message ) {
270278 return normalizedTypes . has ( message . type ( ) ) ;
271279 }
280+ if ( message instanceof AggregatedIssue ) {
281+ return normalizedTypes . has ( 'issue' ) ;
282+ }
272283 return normalizedTypes . has ( 'error' ) ;
273284 } ) ;
274285 }
275286
276- consoleListData = await Promise . all (
277- messages . map ( async ( item ) : Promise < ConsoleMessageData > => {
278- const consoleMessageStableId =
279- context . getConsoleMessageStableId ( item ) ;
280- if ( 'args' in item ) {
281- const consoleMessage = item as ConsoleMessage ;
287+ consoleListData = (
288+ await Promise . all (
289+ messages . map ( async ( item ) : Promise < ConsoleMessageData | null > => {
290+ const consoleMessageStableId =
291+ context . getConsoleMessageStableId ( item ) ;
292+ if ( 'args' in item ) {
293+ const consoleMessage = item as ConsoleMessage ;
294+ return {
295+ consoleMessageStableId,
296+ type : consoleMessage . type ( ) ,
297+ message : consoleMessage . text ( ) ,
298+ args : await Promise . all (
299+ consoleMessage . args ( ) . map ( async arg => {
300+ const stringArg = await arg . jsonValue ( ) . catch ( ( ) => {
301+ // Ignore errors.
302+ } ) ;
303+ return typeof stringArg === 'object'
304+ ? JSON . stringify ( stringArg )
305+ : String ( stringArg ) ;
306+ } ) ,
307+ ) ,
308+ } ;
309+ }
310+ if ( item instanceof AggregatedIssue ) {
311+ const count = item . getAggregatedIssuesCount ( ) ;
312+ const filename = item . getDescription ( ) ?. file ;
313+ const rawMarkdown = filename
314+ ? getIssueDescription ( filename )
315+ : null ;
316+ if ( ! rawMarkdown ) {
317+ logger ( `no markdown ${ filename } found for issue:` + item . code ) ;
318+ return null ;
319+ }
320+ const markdownAst = Marked . Marked . lexer ( rawMarkdown ) ;
321+ const title = findTitleFromMarkdownAst ( markdownAst ) ;
322+ if ( ! title ) {
323+ logger ( 'cannot read issue title from ' + filename ) ;
324+ return null ;
325+ }
326+ return {
327+ consoleMessageStableId,
328+ type : 'issue' ,
329+ item,
330+ message : title ,
331+ count,
332+ args : [ ] ,
333+ } ;
334+ }
282335 return {
283336 consoleMessageStableId,
284- type : consoleMessage . type ( ) ,
285- message : consoleMessage . text ( ) ,
286- args : await Promise . all (
287- consoleMessage . args ( ) . map ( async arg => {
288- const stringArg = await arg . jsonValue ( ) . catch ( ( ) => {
289- // Ignore errors.
290- } ) ;
291- return typeof stringArg === 'object'
292- ? JSON . stringify ( stringArg )
293- : String ( stringArg ) ;
294- } ) ,
295- ) ,
337+ type : 'error' ,
338+ message : ( item as Error ) . message ,
339+ args : [ ] ,
296340 } ;
297- }
298- return {
299- consoleMessageStableId,
300- type : 'error' ,
301- message : ( item as Error ) . message ,
302- args : [ ] ,
303- } ;
304- } ) ,
305- ) ;
341+ } ) ,
342+ )
343+ ) . filter ( item => item !== null ) ;
306344 }
307345
308346 return this . format ( toolName , context , {
0 commit comments