@@ -8,6 +8,8 @@ import { Logger } from "../logger"
88export const WINDOWS_CMD_EXTENSIONS = new Set ( [ ".cmd" , ".bat" ] )
99export const WINDOWS_POWERSHELL_EXTENSIONS = new Set ( [ ".ps1" ] )
1010
11+ const VERSION_REGEX = / ( [ 0 - 9 ] + \. [ 0 - 9 ] + \. [ 0 - 9 A - Z a - z . - ] + ) /
12+
1113export function buildSpawnSpec ( binaryPath : string , args : string [ ] ) {
1214 if ( process . platform !== "win32" ) {
1315 return { command : binaryPath , args, options : { } as const }
@@ -40,6 +42,61 @@ export function buildSpawnSpec(binaryPath: string, args: string[]) {
4042 return { command : binaryPath , args, options : { } as const }
4143}
4244
45+ export function probeBinaryVersion ( binaryPath : string ) : {
46+ valid : boolean
47+ version ?: string
48+ reported ?: string
49+ error ?: string
50+ } {
51+ if ( ! binaryPath ) {
52+ return { valid : false , error : "Missing binary path" }
53+ }
54+
55+ const spec = buildSpawnSpec ( binaryPath , [ "--version" ] )
56+
57+ try {
58+ const result = spawnSync ( spec . command , spec . args , {
59+ encoding : "utf8" ,
60+ windowsVerbatimArguments : Boolean (
61+ ( spec . options as { windowsVerbatimArguments ?: boolean } ) . windowsVerbatimArguments ,
62+ ) ,
63+ } )
64+
65+ if ( result . error ) {
66+ return { valid : false , error : result . error . message }
67+ }
68+
69+ if ( result . status !== 0 ) {
70+ const stderr = result . stderr ?. trim ( )
71+ const stdout = result . stdout ?. trim ( )
72+ const combined = stderr || stdout
73+ const error = combined ? `Exited with code ${ result . status } : ${ combined } ` : `Exited with code ${ result . status } `
74+ return { valid : false , error }
75+ }
76+
77+ const stdoutLines = String ( result . stdout ?? "" )
78+ . split ( / \r ? \n / )
79+ . map ( ( line ) => line . trim ( ) )
80+ . filter ( ( line ) => line . length > 0 )
81+ const stderrLines = String ( result . stderr ?? "" )
82+ . split ( / \r ? \n / )
83+ . map ( ( line ) => line . trim ( ) )
84+ . filter ( ( line ) => line . length > 0 )
85+
86+ // Prefer stdout; fall back to stderr (some tools report version there).
87+ const reported = stdoutLines [ 0 ] ?? stderrLines [ 0 ]
88+ if ( ! reported ) {
89+ return { valid : true }
90+ }
91+
92+ const versionMatch = reported . match ( VERSION_REGEX )
93+ const version = versionMatch ?. [ 1 ]
94+ return { valid : true , version, reported }
95+ } catch ( error ) {
96+ return { valid : false , error : error instanceof Error ? error . message : String ( error ) }
97+ }
98+ }
99+
43100const SENSITIVE_ENV_KEY = / ( P A S S W O R D | T O K E N | S E C R E T ) / i
44101
45102function redactEnvironment ( env : Record < string , string | undefined > ) : Record < string , string | undefined > {
0 commit comments