@@ -32,6 +32,7 @@ import {
3232 MissingListenerApiKeyError ,
3333 resolveListenerRegistrationOptions ,
3434} from "@/websocket/listener/auth" ;
35+ import { flushRemoteSettingsWrites } from "@/websocket/listener/remote-settings" ;
3536
3637type ListenerProcessAnchor = {
3738 close : ( ) => void ;
@@ -269,13 +270,18 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
269270 await settingsManager . initialize ( ) ;
270271 await applyStartupPermissionMode ( { } ) ;
271272 telemetry . setSurface ( getListenerTelemetrySurface ( ) ) ;
272- telemetry . init ( ) ;
273+ telemetry . init ( { handleSigint : false } ) ;
273274
274275 // Register signal handlers so the listener can clean up child processes
275276 // (subagents, bash commands, PTY sessions) before exiting. Without these,
276277 // SIGTERM from the desktop app only kills the listener process itself,
277278 // orphaning its descendants which accumulate over time.
278- const handleShutdownSignal = async ( ) : Promise < void > => {
279+ let isShuttingDown = false ;
280+ const handleShutdownSignal = async (
281+ signal : "SIGINT" | "SIGHUP" | "SIGTERM" ,
282+ ) : Promise < void > => {
283+ if ( isShuttingDown ) return ;
284+ isShuttingDown = true ;
279285 try {
280286 const { stopListenerClient, isListenerActive } = await import (
281287 "@/websocket/listen-client"
@@ -292,11 +298,14 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
292298 } catch {
293299 // Best-effort cleanup — don't block exit
294300 }
301+ await flushRemoteSettingsWrites ( ) ;
302+ await flushListenerTelemetryEnd ( `listener_${ signal . toLowerCase ( ) } ` ) ;
295303 process . exit ( 0 ) ;
296304 } ;
297305
298- process . once ( "SIGTERM" , handleShutdownSignal ) ;
299- process . once ( "SIGINT" , handleShutdownSignal ) ;
306+ process . once ( "SIGTERM" , ( ) => void handleShutdownSignal ( "SIGTERM" ) ) ;
307+ process . once ( "SIGINT" , ( ) => void handleShutdownSignal ( "SIGINT" ) ) ;
308+ process . once ( "SIGHUP" , ( ) => void handleShutdownSignal ( "SIGHUP" ) ) ;
300309
301310 const exitWithTelemetry = async (
302311 code : number ,
@@ -312,6 +321,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
312321 } catch {
313322 // Best effort — don't block exit on channel cleanup failure
314323 }
324+ await flushRemoteSettingsWrites ( ) ;
315325 await flushListenerTelemetryEnd ( exitReason ) ;
316326 process . exit ( code ) ;
317327 } ;
@@ -772,6 +782,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
772782 const msg = error instanceof Error ? error . message : String ( error ) ;
773783 sessionLog . log ( `FATAL: ${ msg } ` ) ;
774784 console . error ( `Failed to start listener: ${ msg } ` ) ;
785+ await flushRemoteSettingsWrites ( ) ;
775786 await flushListenerTelemetryEnd ( "listener_start_failed" ) ;
776787 return 1 ;
777788 }
0 commit comments