@@ -69,11 +69,13 @@ import {
6969 setFocusedInputValue ,
7070 typeIntoElement ,
7171} from '@/main/browser-agent/page-functions'
72+ import { isPanelVisible , panelWindow } from '@/main/browser-agent/panel'
7273import { withPostActionObservation } from '@/main/browser-agent/post-action-observation'
7374import * as session from '@/main/browser-agent/session'
7475import { checkAgentUrl } from '@/main/browser-agent/url-guard'
7576import { clearCredentials , fillCoordinator , initFillCoordinator } from '@/main/browser-credentials'
7677import type { ConfigStore } from '@/main/config'
78+ import { trackInputActivity } from '@/main/input-activity'
7779
7880const logger = createLogger ( 'BrowserAgentDriver' )
7981
@@ -506,6 +508,7 @@ function pushTabsState(): void {
506508
507509/** Instruments a fresh tab: CDP dialog handling + page-state pushes. */
508510function instrumentTab ( contents : WebContents ) : void {
511+ trackInputActivity ( contents )
509512 const scopeId = session . browserScopeIdForContents ( contents ) ?? session . getBrowserScopeId ( )
510513 const inScope =
511514 < Args extends unknown [ ] > ( fn : ( ...args : Args ) => void ) =>
@@ -625,6 +628,35 @@ export function initDriver(
625628 // leaving the old chain head in place would queue the new session's first
626629 // tool call behind a promise nothing can ever settle.
627630 initFillCoordinator ( {
631+ pickerHost : ( contents , bounds ) => {
632+ const scopeId = session . getActiveBrowserScopeId ( )
633+ const window = panelWindow ( )
634+ if ( ! scopeId || ! window || window . isDestroyed ( ) || ! window . isVisible ( ) || ! isPanelVisible ( ) )
635+ return null
636+ return session . withBrowserScope ( scopeId , ( ) => {
637+ const tab = session . activeTab ( )
638+ if ( ! tab || tab . view . webContents !== contents || ! tab . view . getVisible ( ) ) return null
639+ const panel = tab . view . getBounds ( )
640+ const content = window . getContentBounds ( )
641+ const zoom = contents . getZoomFactor ( )
642+ if (
643+ bounds . x + bounds . width <= 0 ||
644+ bounds . y + bounds . height <= 0 ||
645+ bounds . x * zoom >= panel . width ||
646+ bounds . y * zoom >= panel . height
647+ )
648+ return null
649+ return {
650+ window,
651+ anchor : {
652+ x : content . x + panel . x + bounds . x * zoom ,
653+ y : content . y + panel . y + bounds . y * zoom ,
654+ width : bounds . width * zoom ,
655+ height : bounds . height * zoom ,
656+ } ,
657+ }
658+ } )
659+ } ,
628660 getActiveContents : ( scopeId ) => {
629661 const activeScopeId = session . getActiveBrowserScopeId ( )
630662 if ( ! activeScopeId ) return null
@@ -646,6 +678,7 @@ export function initDriver(
646678 } )
647679 session . initSession (
648680 {
681+ onPanelGeometryChanged : ( ) => fillCoordinator ( ) ?. dismissPicker ( ) ,
649682 onSessionClosed : ( ) => {
650683 driverCallbacks ?. onSessionStatus ( false , session . getBrowserScopeId ( ) )
651684 } ,
@@ -748,6 +781,14 @@ export function showToolbarMenu(
748781 ] ,
749782 } ,
750783 { type : 'separator' } ,
784+ {
785+ label : 'Fill Saved Password' ,
786+ enabled : pageAvailable ,
787+ click : ( ) => {
788+ void fillCoordinator ( ) ?. showChooser ( ownerWindow , anchor , resolved )
789+ } ,
790+ } ,
791+ { label : 'Passwords' , click : ( ) => sendCommand ( 'passwords' ) } ,
751792 { label : 'Import Passwords' , click : ( ) => sendCommand ( 'import' ) } ,
752793 { type : 'separator' } ,
753794 { label : 'Browser Settings' , click : ( ) => sendCommand ( 'browser-settings' ) } ,
0 commit comments