@@ -23,7 +23,7 @@ import { getLlmGatewayUrl } from "@posthog/agent/posthog-api";
2323import type { OnLogCallback } from "@posthog/agent/types" ;
2424import { isAuthError } from "@shared/errors.js" ;
2525import type { AcpMessage } from "@shared/types/session-events.js" ;
26- import { app } from "electron" ;
26+ import { app , powerMonitor } from "electron" ;
2727import { inject , injectable , preDestroy } from "inversify" ;
2828import { MAIN_TOKENS } from "../../di/tokens.js" ;
2929import { isDevBuild } from "../../utils/env.js" ;
@@ -258,7 +258,10 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
258258 private currentToken : string | null = null ;
259259 private pendingPermissions = new Map < string , PendingPermission > ( ) ;
260260 private mockNodeReady = false ;
261- private idleTimeoutHandles = new Map < string , ReturnType < typeof setTimeout > > ( ) ;
261+ private idleTimeouts = new Map <
262+ string ,
263+ { handle : ReturnType < typeof setTimeout > ; deadline : number }
264+ > ( ) ;
262265 private processTracking : ProcessTrackingService ;
263266 private sleepService : SleepService ;
264267 private fsService : FsService ;
@@ -279,6 +282,8 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
279282 this . sleepService = sleepService ;
280283 this . fsService = fsService ;
281284 this . posthogPluginService = posthogPluginService ;
285+
286+ powerMonitor . on ( "resume" , ( ) => this . checkIdleDeadlines ( ) ) ;
282287 }
283288
284289 public updateToken ( newToken : string ) : void {
@@ -397,34 +402,40 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
397402 return false ;
398403 }
399404
400- public reportActivity ( taskId : string | null ) : void {
401- if ( ! taskId ) return ;
402- for ( const session of this . sessions . values ( ) ) {
403- if ( session . taskId === taskId ) {
404- this . recordActivity ( session . taskRunId ) ;
405- }
406- }
407- }
408-
409- private recordActivity ( taskRunId : string ) : void {
410- const existing = this . idleTimeoutHandles . get ( taskRunId ) ;
411- if ( existing ) clearTimeout ( existing ) ;
405+ public recordActivity ( taskRunId : string ) : void {
406+ const existing = this . idleTimeouts . get ( taskRunId ) ;
407+ if ( existing ) clearTimeout ( existing . handle ) ;
412408
409+ const deadline = Date . now ( ) + AgentService . IDLE_TIMEOUT_MS ;
413410 const handle = setTimeout ( ( ) => {
414- this . idleTimeoutHandles . delete ( taskRunId ) ;
415- const session = this . sessions . get ( taskRunId ) ;
416- if ( ! session || session . promptPending ) return ;
417- log . info ( "Killing idle session" , { taskRunId, taskId : session . taskId } ) ;
418- this . emit ( AgentServiceEvent . SessionIdleKilled , {
419- taskRunId,
420- taskId : session . taskId ,
421- } ) ;
422- this . cleanupSession ( taskRunId ) . catch ( ( err ) => {
423- log . error ( "Failed to cleanup idle session" , { taskRunId, err } ) ;
424- } ) ;
411+ this . killIdleSession ( taskRunId ) ;
425412 } , AgentService . IDLE_TIMEOUT_MS ) ;
426413
427- this . idleTimeoutHandles . set ( taskRunId , handle ) ;
414+ this . idleTimeouts . set ( taskRunId , { handle, deadline } ) ;
415+ }
416+
417+ private killIdleSession ( taskRunId : string ) : void {
418+ this . idleTimeouts . delete ( taskRunId ) ;
419+ const session = this . sessions . get ( taskRunId ) ;
420+ if ( ! session || session . promptPending ) return ;
421+ log . info ( "Killing idle session" , { taskRunId, taskId : session . taskId } ) ;
422+ this . emit ( AgentServiceEvent . SessionIdleKilled , {
423+ taskRunId,
424+ taskId : session . taskId ,
425+ } ) ;
426+ this . cleanupSession ( taskRunId ) . catch ( ( err ) => {
427+ log . error ( "Failed to cleanup idle session" , { taskRunId, err } ) ;
428+ } ) ;
429+ }
430+
431+ private checkIdleDeadlines ( ) : void {
432+ const now = Date . now ( ) ;
433+ for ( const [ taskRunId , { handle, deadline } ] of this . idleTimeouts ) {
434+ if ( now >= deadline ) {
435+ clearTimeout ( handle ) ;
436+ this . killIdleSession ( taskRunId ) ;
437+ }
438+ }
428439 }
429440
430441 private getToken ( fallback : string ) : string {
@@ -821,6 +832,7 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
821832 } ;
822833
823834 this . sessions . set ( taskRunId , session ) ;
835+ this . recordActivity ( taskRunId ) ;
824836 if ( isRetry ) {
825837 log . info ( "Session created after auth retry" , { taskRunId } ) ;
826838 }
@@ -1176,8 +1188,8 @@ For git operations while detached:
11761188
11771189 @preDestroy ( )
11781190 async cleanupAll ( ) : Promise < void > {
1179- for ( const handle of this . idleTimeoutHandles . values ( ) ) clearTimeout ( handle ) ;
1180- this . idleTimeoutHandles . clear ( ) ;
1191+ for ( const { handle } of this . idleTimeouts . values ( ) ) clearTimeout ( handle ) ;
1192+ this . idleTimeouts . clear ( ) ;
11811193 const sessionIds = Array . from ( this . sessions . keys ( ) ) ;
11821194 log . info ( "Cleaning up all agent sessions" , {
11831195 sessionCount : sessionIds . length ,
@@ -1265,10 +1277,10 @@ For git operations while detached:
12651277
12661278 this . sessions . delete ( taskRunId ) ;
12671279
1268- const handle = this . idleTimeoutHandles . get ( taskRunId ) ;
1269- if ( handle ) {
1270- clearTimeout ( handle ) ;
1271- this . idleTimeoutHandles . delete ( taskRunId ) ;
1280+ const timeout = this . idleTimeouts . get ( taskRunId ) ;
1281+ if ( timeout ) {
1282+ clearTimeout ( timeout . handle ) ;
1283+ this . idleTimeouts . delete ( taskRunId ) ;
12721284 }
12731285 }
12741286 }
0 commit comments