@@ -563,37 +563,23 @@ const createCliBuilder = <V, P extends readonly unknown[]>(
563563 parentGlobals : ParseResult < unknown , readonly unknown [ ] > ,
564564 allowAsync : boolean ,
565565 ) :
566- | ( ParseResult < V , P > & { command ?: string ; earlyExit ?: boolean } )
567- | Promise < ParseResult < V , P > & { command ?: string ; earlyExit ?: boolean } > {
566+ | ( ParseResult < V , P > & { command ?: string } )
567+ | Promise < ParseResult < V , P > & { command ?: string } > {
568568 const stateWithGlobals = { ...state , parentGlobals } ;
569569 try {
570570 const result = parseCore ( stateWithGlobals , args , allowAsync ) ;
571571 if ( isThenable ( result ) ) {
572572 return result . catch ( ( error : unknown ) => {
573573 if ( error instanceof HelpError ) {
574- return handleHelpError ( error , stateWithGlobals ) as ParseResult <
575- V ,
576- P
577- > & {
578- command ?: string ;
579- earlyExit : true ;
580- } ;
574+ handleHelpError ( error , stateWithGlobals ) ; // exits process
581575 }
582576 throw error ;
583- } ) as Promise <
584- ParseResult < V , P > & { command ?: string ; earlyExit ?: boolean }
585- > ;
577+ } ) as Promise < ParseResult < V , P > & { command ?: string } > ;
586578 }
587579 return result as ParseResult < V , P > & { command ?: string } ;
588580 } catch ( error ) {
589581 if ( error instanceof HelpError ) {
590- return handleHelpError ( error , stateWithGlobals ) as ParseResult <
591- V ,
592- P
593- > & {
594- command ?: string ;
595- earlyExit : true ;
596- } ;
582+ handleHelpError ( error , stateWithGlobals ) ; // exits process
597583 }
598584 throw error ;
599585 }
@@ -789,7 +775,7 @@ const createCliBuilder = <V, P extends readonly unknown[]>(
789775
790776 parse (
791777 args : string [ ] = process . argv . slice ( 2 ) ,
792- ) : ParseResult < V , P > & { command ?: string ; earlyExit ?: boolean } {
778+ ) : ParseResult < V , P > & { command ?: string } {
793779 try {
794780 const result = parseCore ( state , args , false ) ;
795781 if ( isThenable ( result ) ) {
@@ -800,28 +786,22 @@ const createCliBuilder = <V, P extends readonly unknown[]>(
800786 return result as ParseResult < V , P > & { command ?: string } ;
801787 } catch ( error ) {
802788 if ( error instanceof HelpError ) {
803- return handleHelpError ( error , state ) as ParseResult < V , P > & {
804- command ?: string ;
805- earlyExit : true ;
806- } ;
789+ handleHelpError ( error , state ) ; // exits process, never returns
807790 }
808791 throw error ;
809792 }
810793 } ,
811794
812795 async parseAsync (
813796 args : string [ ] = process . argv . slice ( 2 ) ,
814- ) : Promise < ParseResult < V , P > & { command ?: string ; earlyExit ?: boolean } > {
797+ ) : Promise < ParseResult < V , P > & { command ?: string } > {
815798 try {
816799 return ( await parseCore ( state , args , true ) ) as ParseResult < V , P > & {
817800 command ?: string ;
818801 } ;
819802 } catch ( error ) {
820803 if ( error instanceof HelpError ) {
821- return handleHelpError ( error , state ) as ParseResult < V , P > & {
822- command ?: string ;
823- earlyExit : true ;
824- } ;
804+ handleHelpError ( error , state ) ; // exits process, never returns
825805 }
826806 throw error ;
827807 }
@@ -849,19 +829,17 @@ const parseCore = (
849829 const { aliasMap, commands, options, theme } = state ;
850830
851831 /**
852- * Helper to create an early-exit result (for help, version, completions).
853- * Sets process.exitCode and returns a result with earlyExit: true.
832+ * Terminates the process for early-exit scenarios (--help, --version,
833+ * --completion-script). This is standard CLI behavior - users expect these
834+ * flags to print output and exit immediately.
854835 *
836+ * @remarks
837+ * The return statement exists only to satisfy TypeScript. In practice,
838+ * `process.exit()` terminates the process and this function never returns.
855839 * @function
856840 */
857- const createEarlyExitResult = (
858- exitCode : number ,
859- ) : ParseResult < unknown , readonly unknown [ ] > & {
860- command ?: string ;
861- earlyExit : true ;
862- } => {
863- process . exitCode = exitCode ;
864- return { command : undefined , earlyExit : true , positionals : [ ] , values : { } } ;
841+ const exitProcess = ( exitCode : number ) : never => {
842+ process . exit ( exitCode ) ;
865843 } ;
866844
867845 // Handle --help
@@ -909,12 +887,12 @@ const parseCore = (
909887
910888 // Regular command help
911889 console . log ( generateCommandHelpNew ( state , commandName , theme ) ) ;
912- return createEarlyExitResult ( 0 ) ;
890+ return exitProcess ( 0 ) ;
913891 }
914892 }
915893
916894 console . log ( generateHelpNew ( state , theme ) ) ;
917- return createEarlyExitResult ( 0 ) ;
895+ return exitProcess ( 0 ) ;
918896 }
919897
920898 // Handle --version
@@ -925,7 +903,7 @@ const parseCore = (
925903 } else {
926904 console . log ( 'Version information not available' ) ;
927905 }
928- return createEarlyExitResult ( 0 ) ;
906+ return exitProcess ( 0 ) ;
929907 }
930908
931909 // Handle shell completion (when enabled)
@@ -938,15 +916,15 @@ const parseCore = (
938916 console . error (
939917 'Error: --completion-script requires a shell argument (bash, zsh, or fish)' ,
940918 ) ;
941- return createEarlyExitResult ( 1 ) ;
919+ return exitProcess ( 1 ) ;
942920 }
943921 try {
944922 const shell = validateShell ( shellArg ) ;
945923 console . log ( generateCompletionScript ( state . name , shell ) ) ;
946- return createEarlyExitResult ( 0 ) ;
924+ return exitProcess ( 0 ) ;
947925 } catch ( err ) {
948926 console . error ( `Error: ${ ( err as Error ) . message } ` ) ;
949- return createEarlyExitResult ( 1 ) ;
927+ return exitProcess ( 1 ) ;
950928 }
951929 }
952930
@@ -956,7 +934,7 @@ const parseCore = (
956934 const shellArg = args [ getCompletionsIndex + 1 ] ;
957935 if ( ! shellArg ) {
958936 // No shell specified, output nothing
959- return createEarlyExitResult ( 0 ) ;
937+ return exitProcess ( 0 ) ;
960938 }
961939 try {
962940 const shell = validateShell ( shellArg ) ;
@@ -966,10 +944,10 @@ const parseCore = (
966944 if ( candidates . length > 0 ) {
967945 console . log ( candidates . join ( '\n' ) ) ;
968946 }
969- return createEarlyExitResult ( 0 ) ;
947+ return exitProcess ( 0 ) ;
970948 } catch {
971949 // Invalid shell, output nothing
972- return createEarlyExitResult ( 0 ) ;
950+ return exitProcess ( 0 ) ;
973951 }
974952 }
975953 }
@@ -985,31 +963,22 @@ const parseCore = (
985963
986964/**
987965 * Show help for a nested command group by delegating to the nested builder.
966+ * This function always terminates the process (either via the nested builder's
967+ * help handling or via error exit).
988968 *
989969 * @function
990970 */
991971const showNestedCommandHelp = (
992972 state : InternalCliState ,
993973 commandName : string ,
994- ) :
995- | ( ParseResult < unknown , readonly unknown [ ] > & {
996- command ?: string ;
997- earlyExit ?: boolean ;
998- } )
999- | Promise <
1000- ParseResult < unknown , readonly unknown [ ] > & {
1001- command ?: string ;
1002- earlyExit ?: boolean ;
1003- }
1004- > => {
974+ ) : never => {
1005975 const commandEntry = state . commands . get ( commandName ) ;
1006976 if ( ! commandEntry || commandEntry . type !== 'nested' ) {
1007977 console . error ( `Unknown command group: ${ commandName } ` ) ;
1008- process . exitCode = 1 ;
1009- return { command : undefined , earlyExit : true , positionals : [ ] , values : { } } ;
978+ process . exit ( 1 ) ;
1010979 }
1011980
1012- // Delegate to nested builder with --help
981+ // Delegate to nested builder with --help - this will exit the process
1013982 const internalNestedBuilder = commandEntry . builder as InternalCliBuilder <
1014983 unknown ,
1015984 readonly unknown [ ]
@@ -1019,12 +988,18 @@ const showNestedCommandHelp = (
1019988 values : { } ,
1020989 } ;
1021990
1022- // This will show the nested builder's help
1023- return internalNestedBuilder . __parseWithParentGlobals (
991+ // This will show the nested builder's help and exit the process.
992+ // The void operator explicitly marks this as intentionally unhandled since
993+ // process.exit() inside will terminate before the promise resolves.
994+ void internalNestedBuilder . __parseWithParentGlobals (
1024995 [ '--help' ] ,
1025996 emptyGlobals ,
1026997 true ,
1027998 ) ;
999+
1000+ // This should never be reached since help handling calls process.exit()
1001+ // but TypeScript needs it for the never return type
1002+ process . exit ( 0 ) ;
10281003} ;
10291004
10301005/**
@@ -1131,13 +1106,15 @@ const generateHelpNew = (state: InternalCliState, theme: Theme): string => {
11311106 *
11321107 * @function
11331108 */
1134- const handleHelpError = (
1135- error : HelpError ,
1136- state : InternalCliState ,
1137- ) : ParseResult < unknown , readonly unknown [ ] > & {
1138- command ?: string ;
1139- earlyExit : true ;
1140- } => {
1109+ /**
1110+ * Handles HelpError by displaying the error message, showing help, and
1111+ * terminating the process with exit code 1. This is standard CLI behavior -
1112+ * when a user provides an unknown command or forgets to specify a required
1113+ * command, they see help and the process exits.
1114+ *
1115+ * @function
1116+ */
1117+ const handleHelpError = ( error : HelpError , state : InternalCliState ) : never => {
11411118 const { theme } = state ;
11421119
11431120 // Write error message to stderr
@@ -1148,16 +1125,8 @@ const handleHelpError = (
11481125 process . stderr . write ( helpText ) ;
11491126 process . stderr . write ( '\n' ) ;
11501127
1151- // Set exit code to indicate error (don't call process.exit())
1152- process . exitCode = 1 ;
1153-
1154- // Return a result indicating help was shown
1155- return {
1156- command : error . command ,
1157- earlyExit : true ,
1158- positionals : [ ] ,
1159- values : { } ,
1160- } ;
1128+ // Terminate with error exit code
1129+ process . exit ( 1 ) ;
11611130} ;
11621131
11631132/**
0 commit comments