@@ -18,11 +18,27 @@ 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+ setupTelemetryExitHandlers ,
24+ trackCliComplete ,
25+ trackCliError ,
26+ trackCliStart ,
27+ } from './utils/telemetry/integration.mts'
2128import { socketPackageLink } from './utils/terminal-link.mts'
2229
2330const __filename = fileURLToPath ( import . meta. url )
2431
32+ // Capture CLI start time at module level for global error handlers.
33+ const cliStartTime = Date . now ( )
34+
35+ // Set up telemetry exit handlers early to catch all exit scenarios.
36+ setupTelemetryExitHandlers ( )
37+
2538void ( async ( ) => {
39+ // Track CLI start for telemetry.
40+ await trackCliStart ( process . argv )
41+
2642 const registryUrl = lookupRegistryUrl ( )
2743 await updateNotifier ( {
2844 authInfo : lookupRegistryAuthToken ( registryUrl , { recursive : true } ) ,
@@ -50,8 +66,14 @@ void (async () => {
5066 } ,
5167 { aliases : rootAliases } ,
5268 )
69+
70+ // Track successful CLI completion.
71+ await trackCliComplete ( process . argv , cliStartTime , process . exitCode )
5372 } catch ( e ) {
5473 process . exitCode = 1
74+
75+ // Track CLI error for telemetry.
76+ await trackCliError ( process . argv , cliStartTime , e , process . exitCode )
5577 debugFn ( 'error' , 'CLI uncaught error' )
5678 debugDir ( 'error' , e )
5779
@@ -105,4 +127,45 @@ void (async () => {
105127
106128 await captureException ( e )
107129 }
108- } ) ( )
130+ } ) ( ) . catch ( async err => {
131+ // Fatal error in main async function.
132+ console . error ( 'Fatal error:' , err )
133+
134+ // Track CLI error for fatal exceptions.
135+ await trackCliError ( process . argv , cliStartTime , err , 1 )
136+
137+ // Finalize telemetry before fatal exit.
138+ await finalizeTelemetry ( )
139+
140+ // eslint-disable-next-line n/no-process-exit
141+ process . exit ( 1 )
142+ } )
143+
144+ // Handle uncaught exceptions.
145+ process . on ( 'uncaughtException' , async err => {
146+ console . error ( 'Uncaught exception:' , err )
147+
148+ // Track CLI error for uncaught exception.
149+ await trackCliError ( process . argv , cliStartTime , err , 1 )
150+
151+ // Finalize telemetry before exit.
152+ await finalizeTelemetry ( )
153+
154+ // eslint-disable-next-line n/no-process-exit
155+ process . exit ( 1 )
156+ } )
157+
158+ // Handle unhandled promise rejections.
159+ process . on ( 'unhandledRejection' , async ( reason , promise ) => {
160+ console . error ( 'Unhandled rejection at:' , promise , 'reason:' , reason )
161+
162+ // Track CLI error for unhandled rejection.
163+ const error = reason instanceof Error ? reason : new Error ( String ( reason ) )
164+ await trackCliError ( process . argv , cliStartTime , error , 1 )
165+
166+ // Finalize telemetry before exit.
167+ await finalizeTelemetry ( )
168+
169+ // eslint-disable-next-line n/no-process-exit
170+ process . exit ( 1 )
171+ } )
0 commit comments