@@ -131,6 +131,27 @@ fn cli_refresh_wsl_token(distro: &str) {
131131 wait_for_refresh ( & mut child) ;
132132}
133133
134+ /// Spawn a command and wait up to `timeout` for it to finish.
135+ /// Returns None if the process fails to start or exceeds the deadline.
136+ fn run_with_timeout ( cmd : & mut Command , timeout : Duration ) -> Option < std:: process:: Output > {
137+ let mut child = cmd. spawn ( ) . ok ( ) ?;
138+ let start = std:: time:: Instant :: now ( ) ;
139+ loop {
140+ match child. try_wait ( ) {
141+ Ok ( Some ( _) ) => return child. wait_with_output ( ) . ok ( ) ,
142+ Ok ( None ) => {
143+ if start. elapsed ( ) > timeout {
144+ let _ = child. kill ( ) ;
145+ let _ = child. wait ( ) ;
146+ return None ;
147+ }
148+ std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
149+ }
150+ Err ( _) => return None ,
151+ }
152+ }
153+ }
154+
134155fn wait_for_refresh ( child : & mut std:: process:: Child ) {
135156 // Wait up to 30 seconds; don't block the poll thread forever.
136157 let start = std:: time:: Instant :: now ( ) ;
@@ -382,18 +403,19 @@ fn read_credentials_from_source(source: &CredentialSource) -> Option<Credentials
382403}
383404
384405fn read_wsl_credentials ( distro : & str ) -> Option < Credentials > {
385- let output = Command :: new ( "wsl.exe" )
386- . arg ( "-d" )
387- . arg ( distro)
388- . arg ( "--" )
389- . arg ( "sh" )
390- . arg ( "-lc" )
391- . arg ( "cat ~/.claude/.credentials.json" )
392- . creation_flags ( CREATE_NO_WINDOW )
393- . stdout ( std:: process:: Stdio :: piped ( ) )
394- . stderr ( std:: process:: Stdio :: null ( ) )
395- . output ( )
396- . ok ( ) ?;
406+ let output = run_with_timeout (
407+ Command :: new ( "wsl.exe" )
408+ . arg ( "-d" )
409+ . arg ( distro)
410+ . arg ( "--" )
411+ . arg ( "sh" )
412+ . arg ( "-lc" )
413+ . arg ( "cat ~/.claude/.credentials.json" )
414+ . creation_flags ( CREATE_NO_WINDOW )
415+ . stdout ( std:: process:: Stdio :: piped ( ) )
416+ . stderr ( std:: process:: Stdio :: null ( ) ) ,
417+ Duration :: from_secs ( 5 ) ,
418+ ) ?;
397419
398420 if !output. status . success ( ) {
399421 return None ;
@@ -435,14 +457,15 @@ fn choose_best_credentials(mut candidates: Vec<Credentials>) -> Option<Credentia
435457}
436458
437459fn list_wsl_distros ( ) -> Vec < String > {
438- let output = match Command :: new ( "wsl.exe" )
439- . args ( [ "-l" , "-q" ] )
440- . creation_flags ( CREATE_NO_WINDOW )
441- . stdout ( std:: process:: Stdio :: piped ( ) )
442- . stderr ( std:: process:: Stdio :: null ( ) )
443- . output ( )
444- {
445- Ok ( output) if output. status . success ( ) => output,
460+ let output = match run_with_timeout (
461+ Command :: new ( "wsl.exe" )
462+ . args ( [ "-l" , "-q" ] )
463+ . creation_flags ( CREATE_NO_WINDOW )
464+ . stdout ( std:: process:: Stdio :: piped ( ) )
465+ . stderr ( std:: process:: Stdio :: null ( ) ) ,
466+ Duration :: from_secs ( 5 ) ,
467+ ) {
468+ Some ( output) if output. status . success ( ) => output,
446469 _ => return Vec :: new ( ) ,
447470 } ;
448471
0 commit comments