@@ -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,43 @@ 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- }
405+ public recordActivity ( taskRunId : string ) : void {
406+ if ( ! this . sessions . has ( taskRunId ) ) return ;
408407
409- private recordActivity ( taskRunId : string ) : void {
410- const existing = this . idleTimeoutHandles . get ( taskRunId ) ;
411- if ( existing ) clearTimeout ( existing ) ;
408+ const existing = this . idleTimeouts . get ( taskRunId ) ;
409+ if ( existing ) clearTimeout ( existing . handle ) ;
412410
411+ const deadline = Date . now ( ) + AgentService . IDLE_TIMEOUT_MS ;
413412 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- } ) ;
413+ this . killIdleSession ( taskRunId ) ;
425414 } , AgentService . IDLE_TIMEOUT_MS ) ;
426415
427- this . idleTimeoutHandles . set ( taskRunId , handle ) ;
416+ this . idleTimeouts . set ( taskRunId , { handle, deadline } ) ;
417+ }
418+
419+ private killIdleSession ( taskRunId : string ) : void {
420+ this . idleTimeouts . delete ( taskRunId ) ;
421+ const session = this . sessions . get ( taskRunId ) ;
422+ if ( ! session || session . promptPending ) return ;
423+ log . info ( "Killing idle session" , { taskRunId, taskId : session . taskId } ) ;
424+ this . emit ( AgentServiceEvent . SessionIdleKilled , {
425+ taskRunId,
426+ taskId : session . taskId ,
427+ } ) ;
428+ this . cleanupSession ( taskRunId ) . catch ( ( err ) => {
429+ log . error ( "Failed to cleanup idle session" , { taskRunId, err } ) ;
430+ } ) ;
431+ }
432+
433+ private checkIdleDeadlines ( ) : void {
434+ const now = Date . now ( ) ;
435+ const expired = [ ...this . idleTimeouts . entries ( ) ] . filter (
436+ ( [ , { deadline } ] ) => now >= deadline ,
437+ ) ;
438+ for ( const [ taskRunId , { handle } ] of expired ) {
439+ clearTimeout ( handle ) ;
440+ this . killIdleSession ( taskRunId ) ;
441+ }
428442 }
429443
430444 private getToken ( fallback : string ) : string {
@@ -821,6 +835,7 @@ export class AgentService extends TypedEventEmitter<AgentServiceEvents> {
821835 } ;
822836
823837 this . sessions . set ( taskRunId , session ) ;
838+ this . recordActivity ( taskRunId ) ;
824839 if ( isRetry ) {
825840 log . info ( "Session created after auth retry" , { taskRunId } ) ;
826841 }
@@ -1176,8 +1191,8 @@ For git operations while detached:
11761191
11771192 @preDestroy ( )
11781193 async cleanupAll ( ) : Promise < void > {
1179- for ( const handle of this . idleTimeoutHandles . values ( ) ) clearTimeout ( handle ) ;
1180- this . idleTimeoutHandles . clear ( ) ;
1194+ for ( const { handle } of this . idleTimeouts . values ( ) ) clearTimeout ( handle ) ;
1195+ this . idleTimeouts . clear ( ) ;
11811196 const sessionIds = Array . from ( this . sessions . keys ( ) ) ;
11821197 log . info ( "Cleaning up all agent sessions" , {
11831198 sessionCount : sessionIds . length ,
@@ -1265,10 +1280,10 @@ For git operations while detached:
12651280
12661281 this . sessions . delete ( taskRunId ) ;
12671282
1268- const handle = this . idleTimeoutHandles . get ( taskRunId ) ;
1269- if ( handle ) {
1270- clearTimeout ( handle ) ;
1271- this . idleTimeoutHandles . delete ( taskRunId ) ;
1283+ const timeout = this . idleTimeouts . get ( taskRunId ) ;
1284+ if ( timeout ) {
1285+ clearTimeout ( timeout . handle ) ;
1286+ this . idleTimeouts . delete ( taskRunId ) ;
12721287 }
12731288 }
12741289 }
0 commit comments