Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/cli/chat/autonomous-claude-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1609,12 +1609,19 @@ You are NOT a cautious assistant - you are a proactive, autonomous developer who
this.keypressHandler = undefined
}

// Remove all event handlers from readline
// Remove event listeners
if (this.rl) {
this.eventHandlers.forEach((handler, event) => {
this.rl.removeListener(event, handler)
})
this.eventHandlers.clear()
this.rl.removeAllListeners()
}

// Remove global process listeners
const sigintHandler = this.eventHandlers.get('SIGINT')
if (sigintHandler) {
process.removeListener('SIGINT', sigintHandler)
}

// Reset raw mode with proper state restoration
Expand Down
30 changes: 30 additions & 0 deletions src/cli/nik-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16936,16 +16936,46 @@ This file is automatically maintained by NikCLI to provide consistent context ac
this.printShutdownLog(`Token status bar cleanup warning: ${error.message}`, 'warning')
}

// Remove global process listeners to prevent memory leaks
const shutdownHandler = this.gracefulShutdown?.bind(this) || (() => {})
process.removeListener('SIGINT', shutdownHandler)
process.removeListener('SIGTERM', shutdownHandler)

// Remove keypress listener to prevent loop
if (this.keypressListener) {
process.stdin.removeListener('keypress', this.keypressListener)
this.keypressListener = undefined
}

if (this.rl) {
// Remove all listeners from readline interface before closing
this.rl.removeAllListeners()
this.rl.close()
}

// Remove auth provider listeners
try {
authProvider.removeAllListeners('signed_in')
authProvider.removeAllListeners('signed_out')
authProvider.removeAllListeners('auto_login_success')
} catch (_e) {
// Ignore auth cleanup errors
}

// Remove agent service listeners
try {
agentService.removeAllListeners('task_start')
agentService.removeAllListeners('task_progress')
agentService.removeAllListeners('tool_use')
agentService.removeAllListeners('task_complete')
agentService.removeAllListeners('file_read')
agentService.removeAllListeners('file_written')
agentService.removeAllListeners('file_list')
agentService.removeAllListeners('grep_results')
} catch (_e) {
// Ignore agent service cleanup errors
}

// Cleanup systems
this.agentManager.cleanup()

Expand Down
7 changes: 7 additions & 0 deletions src/cli/unified-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,13 @@ export class UnifiedChatInterface extends EventEmitter {
this.rl.removeListener(event, handler)
})
this.eventHandlers.clear()
this.rl.removeAllListeners()
}

// Remove global process listeners
const sigintHandler = this.eventHandlers.get('SIGINT')
if (sigintHandler) {
process.removeListener('SIGINT', sigintHandler)
}

// Clear session data
Expand Down
5 changes: 5 additions & 0 deletions src/cli/unified-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const gracefulShutdown = (signal: string) => {
} catch (error) {
console.error('Error during shutdown:', error)
} finally {
// Remove listeners before exit to prevent memory leaks in case of multiple starts
process.removeAllListeners('SIGINT')
process.removeAllListeners('SIGTERM')
process.removeAllListeners('uncaughtException')
process.removeAllListeners('unhandledRejection')
process.exit(0)
}
}
Expand Down