@@ -18,11 +18,20 @@ import { AuthError, InputError, captureException } from './utils/errors.mts'
1818import { failMsgWithBadge } from './utils/fail-msg-with-badge.mts'
1919import { meowWithSubcommands } from './utils/meow-with-subcommands.mts'
2020import { serializeResultJson } from './utils/serialize-result-json.mts'
21+ import {
22+ finalizeTelemetry ,
23+ trackCliComplete ,
24+ trackCliError ,
25+ trackCliStart ,
26+ } from './utils/telemetry/integration.mts'
2127import { socketPackageLink } from './utils/terminal-link.mts'
2228
2329const __filename = fileURLToPath ( import . meta. url )
2430
2531void ( async ( ) => {
32+ // Track CLI start for telemetry.
33+ const cliStartTime = await trackCliStart ( process . argv )
34+
2635 const registryUrl = lookupRegistryUrl ( )
2736 await updateNotifier ( {
2837 authInfo : lookupRegistryAuthToken ( registryUrl , { recursive : true } ) ,
@@ -50,8 +59,14 @@ void (async () => {
5059 } ,
5160 { aliases : rootAliases } ,
5261 )
62+
63+ // Track successful CLI completion.
64+ await trackCliComplete ( process . argv , cliStartTime , process . exitCode )
5365 } catch ( e ) {
5466 process . exitCode = 1
67+
68+ // Track CLI error for telemetry.
69+ await trackCliError ( process . argv , cliStartTime , e , process . exitCode )
5570 debugFn ( 'error' , 'CLI uncaught error' )
5671 debugDir ( 'error' , e )
5772
@@ -104,5 +119,50 @@ void (async () => {
104119 }
105120
106121 await captureException ( e )
122+ } finally {
123+ // Finalize telemetry to ensure all events are sent.
124+ // This runs on both success and error paths.
125+ await finalizeTelemetry ( )
107126 }
108- } ) ( )
127+ } ) ( ) . catch ( async err => {
128+ // Fatal error in main async function.
129+ console . error ( 'Fatal error:' , err )
130+
131+ // Track CLI error for fatal exceptions.
132+ await trackCliError ( process . argv , Date . now ( ) , err , 1 )
133+
134+ // Finalize telemetry before fatal exit.
135+ await finalizeTelemetry ( )
136+
137+ // eslint-disable-next-line n/no-process-exit
138+ process . exit ( 1 )
139+ } )
140+
141+ // Handle uncaught exceptions.
142+ process . on ( 'uncaughtException' , async err => {
143+ console . error ( 'Uncaught exception:' , err )
144+
145+ // Track CLI error for uncaught exception.
146+ await trackCliError ( process . argv , Date . now ( ) , err , 1 )
147+
148+ // Finalize telemetry before exit.
149+ await finalizeTelemetry ( )
150+
151+ // eslint-disable-next-line n/no-process-exit
152+ process . exit ( 1 )
153+ } )
154+
155+ // Handle unhandled promise rejections.
156+ process . on ( 'unhandledRejection' , async ( reason , promise ) => {
157+ console . error ( 'Unhandled rejection at:' , promise , 'reason:' , reason )
158+
159+ // Track CLI error for unhandled rejection.
160+ const error = reason instanceof Error ? reason : new Error ( String ( reason ) )
161+ await trackCliError ( process . argv , Date . now ( ) , error , 1 )
162+
163+ // Finalize telemetry before exit.
164+ await finalizeTelemetry ( )
165+
166+ // eslint-disable-next-line n/no-process-exit
167+ process . exit ( 1 )
168+ } )
0 commit comments