From 35376658061cc35aaf9316eca3100af6d0445357 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 29 Jul 2026 04:19:04 +0800 Subject: [PATCH] fix(subprocess): honor Windows environment key casing --- packages/subprocess/subprocess-local/src/index.ts | 12 ++++++++++-- .../subprocess/subprocess-local/tests/local.spec.ts | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/subprocess/subprocess-local/src/index.ts b/packages/subprocess/subprocess-local/src/index.ts index 03755cd9ea..4c5cad8018 100644 --- a/packages/subprocess/subprocess-local/src/index.ts +++ b/packages/subprocess/subprocess-local/src/index.ts @@ -102,9 +102,9 @@ export class LocalSubprocessService extends SubprocessService { } private executableCandidates(command: string, env: NodeJS.ProcessEnv): string[] { - const path = env.PATH ?? '' + const path = environmentValue(env, 'PATH') ?? '' const extensions = process.platform === 'win32' && extname(command) === '' - ? (env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD').split(';') + ? (environmentValue(env, 'PATHEXT') ?? '.COM;.EXE;.BAT;.CMD').split(';') : [''] return path.split(delimiter).flatMap(directory => directory === '' ? [] : extensions.map(extension => resolve(this.cwd, directory, command + extension))) @@ -156,4 +156,12 @@ export class LocalSubprocessService extends SubprocessService { } } +/** Read a Windows environment key using the platform's case-insensitive semantics. */ +function environmentValue(env: NodeJS.ProcessEnv, name: 'PATH' | 'PATHEXT'): string | undefined { + const exact = env[name] + if (exact !== undefined || process.platform !== 'win32') return exact + const normalized = name.toUpperCase() + return Object.entries(env).find(([key]) => key.toUpperCase() === normalized)?.[1] +} + export default LocalSubprocessService diff --git a/packages/subprocess/subprocess-local/tests/local.spec.ts b/packages/subprocess/subprocess-local/tests/local.spec.ts index 6ce3d06b8e..4662283aad 100644 --- a/packages/subprocess/subprocess-local/tests/local.spec.ts +++ b/packages/subprocess/subprocess-local/tests/local.spec.ts @@ -62,8 +62,10 @@ describe('LocalSubprocessService', () => { }).executableCandidates.bind(service) const platform = vi.spyOn(process, 'platform', 'get').mockReturnValue('win32') try { - expect(candidates('tool', { PATH: `${delimiter}/bin`, PATHEXT: '.EXE;.CMD' })) + expect(candidates('tool', { Path: `${delimiter}/bin`, PathExt: '.EXE;.CMD' })) .toEqual(['/bin/tool.EXE', '/bin/tool.CMD']) + expect(candidates('tool', { Path: '/ambient', PATH: '/explicit', PATHEXT: '.EXE' })) + .toEqual(['/explicit/tool.EXE']) expect(candidates('tool.exe', {})).toEqual([]) expect(candidates('tool', { PATH: '/bin' })).toHaveLength(4) } finally {