@@ -385,13 +385,37 @@ function isHeadlessLikely(env: NodeJS.ProcessEnv): boolean {
385385 return ! env . DISPLAY && ! env . WAYLAND_DISPLAY && ! env . TERM_PROGRAM ;
386386}
387387
388- function detectNvidiaGpu ( runCaptureImpl : RunCaptureFn ) : boolean {
389- if ( ! commandExists ( "nvidia-smi" , runCaptureImpl ) ) {
390- return false ;
391- }
392- return Boolean ( String ( runCaptureImpl ( [ "nvidia-smi" , "-L" ] , { ignoreError : true } ) || "" ) . trim ( ) ) ;
388+ /**
389+ * Detects NVIDIA hardware via nvidia-smi first, then Linux PCI data as a toolkit-free fallback.
390+ */
391+ function detectNvidiaGpu ( opts : {
392+ platform : NodeJS . Platform | string ;
393+ isWsl : boolean ;
394+ runCaptureImpl : RunCaptureFn ;
395+ commandExistsImpl ?: ( commandName : string ) => boolean ;
396+ } ) : boolean {
397+ const commandExistsImpl =
398+ opts . commandExistsImpl ??
399+ ( ( commandName : string ) => commandExists ( commandName , opts . runCaptureImpl ) ) ;
400+ if ( commandExistsImpl ( "nvidia-smi" ) ) {
401+ const smiOutput = opts . runCaptureImpl ( [ "nvidia-smi" , "-L" ] , { ignoreError : true } ) ;
402+ if ( String ( smiOutput || "" ) . trim ( ) ) return true ;
403+ }
404+
405+ if ( opts . platform !== "linux" || opts . isWsl || ! commandExistsImpl ( "lspci" ) ) return false ;
406+ const pciOutput = opts . runCaptureImpl ( [ "lspci" , "-nn" ] , { ignoreError : true } ) ;
407+ return String ( pciOutput || "" )
408+ . split ( / \r ? \n / )
409+ . some (
410+ ( line ) =>
411+ / n v i d i a / i. test ( line ) &&
412+ / ( v g a c o m p a t i b l e c o n t r o l l e r | 3 d c o n t r o l l e r | d i s p l a y c o n t r o l l e r ) / i. test ( line ) ,
413+ ) ;
393414}
394415
416+ /**
417+ * Detects the host package manager used for NVIDIA toolkit remediation commands.
418+ */
395419function detectPackageManager ( runCaptureImpl : RunCaptureFn ) : PackageManager {
396420 if ( commandExists ( "apt-get" , runCaptureImpl ) ) return "apt" ;
397421 if ( commandExists ( "dnf" , runCaptureImpl ) ) return "dnf" ;
@@ -401,6 +425,9 @@ function detectPackageManager(runCaptureImpl: RunCaptureFn): PackageManager {
401425 return "unknown" ;
402426}
403427
428+ /**
429+ * Normalizes systemctl active/enabled output into a tri-state service status.
430+ */
404431function parseSystemctlState ( value = "" ) : boolean | null {
405432 const normalized = String ( value || "" )
406433 . trim ( )
@@ -447,6 +474,9 @@ export function buildContainerToolkitBootstrapCommands(
447474 ] ;
448475}
449476
477+ /**
478+ * Builds the host capability snapshot used to plan preflight remediation.
479+ */
450480export function assessHost ( opts : AssessHostOpts = { } ) : HostAssessment {
451481 const platform = opts . platform ?? process . platform ;
452482 const env = opts . env ?? process . env ;
@@ -456,12 +486,33 @@ export function assessHost(opts: AssessHostOpts = {}): HostAssessment {
456486 runCapture ( command , { ignoreError : options ?. ignoreError ?? false } ) ) ;
457487 const readFileImpl = opts . readFileImpl ?? fs . readFileSync ;
458488 const readdirImpl = opts . readdirImpl ?? ( ( dir : string ) => fs . readdirSync ( dir ) ) ;
489+ const shouldReadLinuxHostDetails = platform === "linux" ;
490+ const release = opts . release ?? ( shouldReadLinuxHostDetails ? os . release ( ) : "" ) ;
491+ const procVersion =
492+ opts . procVersion ??
493+ ( shouldReadLinuxHostDetails
494+ ? ( ( ) => {
495+ try {
496+ return readFileImpl ( "/proc/version" , "utf-8" ) ;
497+ } catch {
498+ return "" ;
499+ }
500+ } ) ( )
501+ : "" ) ;
502+ const isWslHost = detectWsl ( { platform, env, release, procVersion } ) ;
459503 const dockerInstalled =
460504 opts . commandExistsImpl ?.( "docker" ) ?? commandExists ( "docker" , runCaptureImpl ) ;
461505 const nodeInstalled = opts . commandExistsImpl ?.( "node" ) ?? commandExists ( "node" , runCaptureImpl ) ;
462506 const openshellInstalled =
463507 opts . commandExistsImpl ?.( "openshell" ) ?? commandExists ( "openshell" , runCaptureImpl ) ;
464- const hasNvidiaGpu = opts . gpuProbeImpl ?.( ) ?? detectNvidiaGpu ( runCaptureImpl ) ;
508+ const hasNvidiaGpu =
509+ opts . gpuProbeImpl ?.( ) ??
510+ detectNvidiaGpu ( {
511+ platform,
512+ isWsl : isWslHost ,
513+ runCaptureImpl,
514+ commandExistsImpl : opts . commandExistsImpl ,
515+ } ) ;
465516 const nvidiaContainerToolkitInstalled =
466517 opts . commandExistsImpl ?.( "nvidia-ctk" ) ?? commandExists ( "nvidia-ctk" , runCaptureImpl ) ;
467518 const packageManager = detectPackageManager ( runCaptureImpl ) ;
@@ -480,22 +531,10 @@ export function assessHost(opts: AssessHostOpts = {}): HostAssessment {
480531 dockerReachable = true ;
481532 dockerRunning = true ;
482533 }
483-
484- const release = opts . release ?? os . release ( ) ;
485- const procVersion =
486- opts . procVersion ??
487- ( ( ) => {
488- try {
489- return readFileImpl ( "/proc/version" , "utf-8" ) ;
490- } catch {
491- return "" ;
492- }
493- } ) ( ) ;
494534 let runtime = inferContainerRuntime ( dockerInfoOutput ) ;
495535 if ( dockerReachable && runtime === "unknown" && platform === "linux" ) {
496536 runtime = "docker" ;
497537 }
498- const isWslHost = detectWsl ( { platform, env, release, procVersion } ) ;
499538 const dockerCgroupVersion = dockerReachable
500539 ? parseDockerCgroupVersion ( dockerInfoOutput )
501540 : "unknown" ;
0 commit comments