@@ -93,6 +93,44 @@ function isFilePath(candidate: string): boolean {
9393 }
9494}
9595
96+ function readCaseInsensitiveEnvironmentValue (
97+ env : NodeJS . ProcessEnv ,
98+ uppercaseKey : string ,
99+ ) : { found : boolean ; value ?: string } {
100+ const titleCaseKey = `${ uppercaseKey . slice ( 0 , 1 ) } ${ uppercaseKey . slice ( 1 ) . toLowerCase ( ) } ` ;
101+ const matchingEntries : Array < [ string , string ] > = [ ] ;
102+ for ( const [ candidateKey , value ] of Object . entries ( env ) ) {
103+ if ( candidateKey . toUpperCase ( ) === uppercaseKey && value !== undefined ) {
104+ matchingEntries . push ( [ candidateKey , value ] ) ;
105+ }
106+ }
107+ const priority = ( candidateKey : string ) =>
108+ candidateKey === uppercaseKey ? 0 : candidateKey === titleCaseKey ? 1 : 2 ;
109+ matchingEntries . sort ( ( [ leftKey ] , [ rightKey ] ) => {
110+ return priority ( leftKey ) - priority ( rightKey ) ;
111+ } ) ;
112+
113+ let firstDefined : string | undefined ;
114+ for ( const [ , value ] of matchingEntries ) {
115+ firstDefined ??= value ;
116+ if ( value . trim ( ) . length > 0 ) {
117+ return { found : true , value } ;
118+ }
119+ }
120+ return firstDefined === undefined ? { found : false } : { found : true , value : firstDefined } ;
121+ }
122+
123+ function resolveEnvironmentValue (
124+ env : NodeJS . ProcessEnv ,
125+ fallbackEnv : NodeJS . ProcessEnv ,
126+ key : string ,
127+ ) : string | undefined {
128+ const configured = readCaseInsensitiveEnvironmentValue ( env , key ) ;
129+ return configured . found
130+ ? configured . value
131+ : readCaseInsensitiveEnvironmentValue ( fallbackEnv , key ) . value ;
132+ }
133+
96134function readCommandToken ( command : string ) : { token : string ; rest : string } | null {
97135 const trimmed = command . trim ( ) ;
98136 if ( ! trimmed ) {
@@ -143,15 +181,13 @@ export function resolveWindowsExecutablePath(command: string, env: NodeJS.Proces
143181 return command ;
144182 }
145183
146- const pathValue = env . PATH ?? env . Path ?? process . env . PATH ?? process . env . Path ?? "" ;
184+ // Windows env keys are case-insensitive, but ProcessEnv objects can contain
185+ // multiple casings. Prefer a usable sibling without discarding an explicitly
186+ // empty search path when every matching entry is blank.
187+ const pathValue = resolveEnvironmentValue ( env , process . env , "PATH" ) ?? "" ;
147188 const pathEntries = normalizeStringEntries ( pathValue . split ( ";" ) ) ;
148189 const hasExtension = path . extname ( command ) . length > 0 ;
149- const pathExtRaw =
150- env . PATHEXT ??
151- env . Pathext ??
152- process . env . PATHEXT ??
153- process . env . Pathext ??
154- ".EXE;.CMD;.BAT;.COM" ;
190+ const pathExtRaw = resolveEnvironmentValue ( env , process . env , "PATHEXT" ) ?? ".EXE;.CMD;.BAT;.COM" ;
155191 const pathExt = hasExtension
156192 ? [ "" ]
157193 : normalizeStringEntries ( pathExtRaw . split ( ";" ) ) . map ( ( ext ) =>
0 commit comments