@@ -31,13 +31,15 @@ import {WaitForHelper} from './WaitForHelper.js';
3131
3232export interface TextSnapshotNode extends SerializedAXNode {
3333 id : string ;
34+ backendNodeId ?: number ;
3435 children : TextSnapshotNode [ ] ;
3536}
3637
3738export interface TextSnapshot {
3839 root : TextSnapshotNode ;
3940 idToNode : Map < string , TextSnapshotNode > ;
4041 snapshotId : string ;
42+ selectedElementUid ?: string ;
4143}
4244
4345interface McpContextOptions {
@@ -378,39 +380,72 @@ export class McpContext implements Context {
378380 return this . #pageToDevToolsPage. get ( page ) ;
379381 }
380382
381- async getDevToolsData ( ) : Promise < undefined | { requestId ?: number } > {
383+ async getDevToolsData ( ) : Promise <
384+ undefined | { requestId ?: number ; uid ?: string }
385+ > {
382386 try {
387+ this . logger ( 'Getting DevTools UI data' )
383388 const selectedPage = this . getSelectedPage ( ) ;
384389 const devtoolsPage = this . getDevToolsPage ( selectedPage ) ;
385- if ( devtoolsPage ) {
386- const cdpRequestId = await devtoolsPage . evaluate ( async ( ) => {
390+ if ( ! devtoolsPage ) {
391+ this . logger ( 'No DevTools page detected' ) ;
392+ return ;
393+ }
394+ const { cdpRequestId, cdpBackendNodeId} = await devtoolsPage . evaluate (
395+ async ( ) => {
387396 // @ts -expect-error no types
388397 const UI = await import ( '/bundled/ui/legacy/legacy.js' ) ;
389398 // @ts -expect-error no types
390399 const SDK = await import ( '/bundled/core/sdk/sdk.js' ) ;
391400 const request = UI . Context . Context . instance ( ) . flavor (
392401 SDK . NetworkRequest . NetworkRequest ,
393402 ) ;
394- return request ?. requestId ( ) ;
395- } ) ;
403+ const node = UI . Context . Context . instance ( ) . flavor (
404+ SDK . DOMModel . DOMNode ,
405+ ) ;
406+ return {
407+ cdpRequestId : request ?. requestId ( ) ,
408+ cdpBackendNodeId : node ?. backendNodeId ( ) ,
409+ } ;
410+ } ,
411+ ) ;
412+ const resolveNetworkRequestId = ( ) => {
396413 if ( ! cdpRequestId ) {
397- this . logger ( 'no context request' ) ;
414+ this . logger ( 'no network request' ) ;
398415 return ;
399416 }
400417 const request = this . #networkCollector. find ( selectedPage , request => {
401418 // @ts -expect-error id is internal.
402419 return request . id === cdpRequestId ;
403420 } ) ;
404421 if ( ! request ) {
405- this . logger ( 'no collected request for ' + cdpRequestId ) ;
422+ this . logger ( 'no network request for ' + cdpRequestId ) ;
406423 return ;
407424 }
408- return {
409- requestId : this . #networkCollector. getIdForResource ( request ) ,
410- } ;
411- } else {
412- this . logger ( 'no devtools page deteched' ) ;
413- }
425+ return this . #networkCollector. getIdForResource ( request ) ;
426+ } ;
427+ const resolveNodeUid = ( ) : string | undefined => {
428+ if ( ! cdpBackendNodeId ) {
429+ this . logger ( 'no cdpBackendNodeId' ) ;
430+ return ;
431+ }
432+ // TODO: index by backendNodeId instead.
433+ const queue = [ this . #textSnapshot?. root ] ;
434+ while ( queue . length ) {
435+ const current = queue . pop ( ) ! ;
436+ if ( current . backendNodeId === cdpBackendNodeId ) {
437+ return current . id ;
438+ }
439+ for ( const child of current . children ) {
440+ queue . push ( child ) ;
441+ }
442+ }
443+ return ;
444+ } ;
445+ return {
446+ requestId : resolveNetworkRequestId ( ) ,
447+ uid : resolveNodeUid ( ) ,
448+ } ;
414449 } catch ( err ) {
415450 this . logger ( 'error getting devtools data' , err ) ;
416451 }
@@ -463,6 +498,10 @@ export class McpContext implements Context {
463498 snapshotId : String ( snapshotId ) ,
464499 idToNode,
465500 } ;
501+ const data = await this . getDevToolsData ( ) ;
502+ if ( data ?. uid ) {
503+ this . #textSnapshot. selectedElementUid = data . uid ;
504+ }
466505 }
467506
468507 getTextSnapshot ( ) : TextSnapshot | null {
0 commit comments