@@ -33,13 +33,16 @@ interface WatchedTerminal {
3333 provider : AgentProvider | null ;
3434 discovery ?: ReturnType < typeof setInterval > ;
3535 discoveryAttempts ?: number ;
36+ discoveryBusy ?: boolean ;
37+ discoveryPersistent ?: boolean ;
3638 tail ?: JournalTail ;
3739}
3840
3941interface JournalTail { path : string ; offset : number ; partial : string ; timer : ReturnType < typeof setInterval > ; busy : boolean }
4042
4143export interface NodeAgentJournalSourceOptions {
4244 readonly codexHome ?: string ;
45+ readonly discoveryAttemptLimit ?: number ;
4346 readonly platform ?: NodeJS . Platform ;
4447 readonly pollMs ?: number ;
4548}
@@ -54,13 +57,15 @@ export class NodeAgentJournalSource implements AgentJournalSource {
5457 private readonly root : string ;
5558 private readonly platform : NodeJS . Platform ;
5659 private readonly pollMs : number ;
60+ private readonly discoveryAttemptLimit : number ;
5761 private listener : AgentJournalListener | undefined ;
5862 private enabled = true ;
5963
6064 constructor ( options : NodeAgentJournalSourceOptions = { } ) {
6165 this . root = resolve ( options . codexHome ?? ( process . env . CODEX_HOME ?. trim ( ) || join ( homedir ( ) , ".codex" ) ) ) ;
6266 this . platform = options . platform ?? process . platform ;
6367 this . pollMs = Math . max ( 50 , options . pollMs ?? POLL_MS ) ;
68+ this . discoveryAttemptLimit = Math . max ( 1 , Math . floor ( options . discoveryAttemptLimit ?? 80 ) ) ;
6469 }
6570
6671 async start ( listener : AgentJournalListener ) : Promise < void > { this . listener = listener ; }
@@ -89,8 +94,9 @@ export class NodeAgentJournalSource implements AgentJournalSource {
8994 const terminal = this . exactTerminal ( identity ) ;
9095 if ( ! terminal ) return ;
9196 terminal . provider = provider ;
92- if ( provider === "codex" ) this . startDiscovery ( terminal ) ;
97+ if ( provider === "codex" ) this . startDiscovery ( terminal , true ) ;
9398 else if ( shellForeground ) this . stopWatching ( terminal ) ;
99+ else this . startDiscovery ( terminal ) ;
94100 }
95101
96102 unregisterTerminal ( identity : ActivitySessionIdentity ) : void {
@@ -113,26 +119,32 @@ export class NodeAgentJournalSource implements AgentJournalSource {
113119 return terminal ?. identity . serverId === identity . serverId && terminal . identity . projectId === identity . projectId ? terminal : undefined ;
114120 }
115121
116- private startDiscovery ( terminal : WatchedTerminal ) : void {
122+ private startDiscovery ( terminal : WatchedTerminal , persistent = false ) : void {
123+ if ( persistent ) terminal . discoveryPersistent = true ;
117124 if ( ! this . enabled || terminal . shellPid === undefined || terminal . tail !== undefined || terminal . discovery !== undefined ) return ;
118125 terminal . discoveryAttempts = 0 ;
119126 const discover = async ( ) => {
120- if ( terminal . tail !== undefined || terminal . shellPid === undefined ) return ;
121- terminal . discoveryAttempts = ( terminal . discoveryAttempts ?? 0 ) + 1 ;
122- const path = await findProcessBoundCodexRollout ( terminal . shellPid , join ( this . root , "sessions" ) , this . platform ) . catch ( ( ) => undefined ) ;
123- if ( ! path ) {
124- if ( ( terminal . discoveryAttempts ?? 0 ) >= 80 && terminal . discovery !== undefined ) {
125- clearInterval ( terminal . discovery ) ; terminal . discovery = undefined ;
127+ if ( terminal . tail !== undefined || terminal . shellPid === undefined || terminal . discoveryBusy ) return ;
128+ terminal . discoveryBusy = true ;
129+ try {
130+ terminal . discoveryAttempts = ( terminal . discoveryAttempts ?? 0 ) + 1 ;
131+ const path = await findProcessBoundCodexRollout ( terminal . shellPid , join ( this . root , "sessions" ) , this . platform ) . catch ( ( ) => undefined ) ;
132+ if ( ! path ) {
133+ if ( ! terminal . discoveryPersistent && ( terminal . discoveryAttempts ?? 0 ) >= this . discoveryAttemptLimit && terminal . discovery !== undefined ) {
134+ clearInterval ( terminal . discovery ) ; terminal . discovery = undefined ;
135+ }
136+ return ;
126137 }
127- return ;
138+ if ( terminal . discovery !== undefined ) clearInterval ( terminal . discovery ) ;
139+ terminal . discovery = undefined ;
140+ await this . startTail ( terminal , path ) . catch ( ( ) => undefined ) ;
141+ } finally {
142+ terminal . discoveryBusy = false ;
128143 }
129- if ( terminal . discovery !== undefined ) clearInterval ( terminal . discovery ) ;
130- terminal . discovery = undefined ;
131- await this . startTail ( terminal , path ) . catch ( ( ) => undefined ) ;
132144 } ;
133- void discover ( ) ;
134145 terminal . discovery = setInterval ( ( ) => void discover ( ) , this . pollMs ) ;
135146 terminal . discovery . unref ?.( ) ;
147+ void discover ( ) ;
136148 }
137149
138150 private async startTail ( terminal : WatchedTerminal , path : string ) : Promise < void > {
@@ -205,6 +217,8 @@ export class NodeAgentJournalSource implements AgentJournalSource {
205217 if ( terminal . tail !== undefined ) clearInterval ( terminal . tail . timer ) ;
206218 terminal . discovery = undefined ;
207219 terminal . discoveryAttempts = undefined ;
220+ terminal . discoveryBusy = undefined ;
221+ terminal . discoveryPersistent = undefined ;
208222 terminal . tail = undefined ;
209223 }
210224}
0 commit comments