@@ -4,6 +4,7 @@ import { defineCommand } from 'citty'
4
4
import { intro } from '@clack/prompts'
5
5
import type { EnvVar } from '@types'
6
6
import consola from 'consola'
7
+ import treeKill from 'tree-kill'
7
8
import { handleCancel , loadShelveConfig } from '../utils'
8
9
import { EnvironmentService , EnvService , ProjectService } from '../services'
9
10
import { DEBUG } from '../constants'
@@ -51,6 +52,49 @@ export default defineCommand({
51
52
52
53
try {
53
54
const isNpx = getNrBinPath ( ) === 'npx'
55
+
56
+ let hasExited = false
57
+ let exitTimeout : NodeJS . Timeout | null = null
58
+ const childPid : number | null = null
59
+
60
+ const cleanupAndExit = ( code : number = 0 ) : void => {
61
+ if ( hasExited ) return
62
+ hasExited = true
63
+
64
+ if ( exitTimeout ) {
65
+ clearTimeout ( exitTimeout )
66
+ }
67
+
68
+ process . exit ( code )
69
+ }
70
+
71
+ const handleSignal = ( signal : string ) : void => {
72
+ consola . info ( `Received ${ signal } , terminating process...` )
73
+
74
+ if ( childPid ) {
75
+ treeKill ( childPid , signal , ( err ) => {
76
+ if ( err && DEBUG ) consola . error ( `Failed to kill process: ${ err } ` )
77
+ } )
78
+
79
+ exitTimeout = setTimeout ( ( ) => {
80
+ consola . warn ( 'Process did not exit gracefully, forcing termination...' )
81
+ if ( childPid ) {
82
+ treeKill ( childPid , 'SIGKILL' , ( ) => {
83
+ cleanupAndExit ( 1 )
84
+ } )
85
+ } else {
86
+ cleanupAndExit ( 1 )
87
+ }
88
+ } , 3000 )
89
+ } else {
90
+ cleanupAndExit ( 0 )
91
+ }
92
+ }
93
+
94
+ [ 'SIGINT' , 'SIGTERM' , 'SIGHUP' ] . forEach ( signal => {
95
+ process . on ( signal , ( ) => handleSignal ( signal ) )
96
+ } )
97
+
54
98
const proc = x (
55
99
getNrBinPath ( ) ,
56
100
isNpx ? [ 'nr' , command ] : [ command ] ,
@@ -62,15 +106,13 @@ export default defineCommand({
62
106
}
63
107
)
64
108
65
- const abortController = new AbortController ( )
66
- process . on ( 'SIGINT' , ( ) => {
67
- consola . info ( 'Exiting...' )
68
- abortController . abort ( )
69
- proc . kill ( )
70
- process . exit ( 0 )
71
- } )
72
-
73
- await proc
109
+ try {
110
+ await proc
111
+ cleanupAndExit ( 0 )
112
+ } catch ( err ) {
113
+ if ( DEBUG ) consola . error ( err )
114
+ cleanupAndExit ( 1 )
115
+ }
74
116
} catch ( error ) {
75
117
if ( DEBUG ) consola . error ( error )
76
118
process . exit ( 1 )
0 commit comments