@@ -133,6 +133,27 @@ fn cli_refresh_wsl_token(distro: &str) {
133133 wait_for_refresh ( & mut child) ;
134134}
135135
136+ /// Spawn a command and wait up to `timeout` for it to finish.
137+ /// Returns None if the process fails to start or exceeds the deadline.
138+ fn run_with_timeout ( cmd : & mut Command , timeout : Duration ) -> Option < std:: process:: Output > {
139+ let mut child = cmd. spawn ( ) . ok ( ) ?;
140+ let start = std:: time:: Instant :: now ( ) ;
141+ loop {
142+ match child. try_wait ( ) {
143+ Ok ( Some ( _) ) => return child. wait_with_output ( ) . ok ( ) ,
144+ Ok ( None ) => {
145+ if start. elapsed ( ) > timeout {
146+ let _ = child. kill ( ) ;
147+ let _ = child. wait ( ) ;
148+ return None ;
149+ }
150+ std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
151+ }
152+ Err ( _) => return None ,
153+ }
154+ }
155+ }
156+
136157fn wait_for_refresh ( child : & mut std:: process:: Child ) {
137158 // Wait up to 30 seconds; don't block the poll thread forever.
138159 let start = std:: time:: Instant :: now ( ) ;
@@ -374,18 +395,19 @@ fn read_credentials_from_source(source: &CredentialSource) -> Option<Credentials
374395}
375396
376397fn read_wsl_credentials ( distro : & str ) -> Option < Credentials > {
377- let output = Command :: new ( "wsl.exe" )
378- . arg ( "-d" )
379- . arg ( distro)
380- . arg ( "--" )
381- . arg ( "sh" )
382- . arg ( "-lc" )
383- . arg ( "cat ~/.claude/.credentials.json" )
384- . creation_flags ( CREATE_NO_WINDOW )
385- . stdout ( std:: process:: Stdio :: piped ( ) )
386- . stderr ( std:: process:: Stdio :: null ( ) )
387- . output ( )
388- . ok ( ) ?;
398+ let output = run_with_timeout (
399+ Command :: new ( "wsl.exe" )
400+ . arg ( "-d" )
401+ . arg ( distro)
402+ . arg ( "--" )
403+ . arg ( "sh" )
404+ . arg ( "-lc" )
405+ . arg ( "cat ~/.claude/.credentials.json" )
406+ . creation_flags ( CREATE_NO_WINDOW )
407+ . stdout ( std:: process:: Stdio :: piped ( ) )
408+ . stderr ( std:: process:: Stdio :: null ( ) ) ,
409+ Duration :: from_secs ( 5 ) ,
410+ ) ?;
389411
390412 if !output. status . success ( ) {
391413 return None ;
@@ -424,14 +446,15 @@ fn choose_best_credentials(mut candidates: Vec<Credentials>) -> Option<Credentia
424446}
425447
426448fn list_wsl_distros ( ) -> Vec < String > {
427- let output = match Command :: new ( "wsl.exe" )
428- . args ( [ "-l" , "-q" ] )
429- . creation_flags ( CREATE_NO_WINDOW )
430- . stdout ( std:: process:: Stdio :: piped ( ) )
431- . stderr ( std:: process:: Stdio :: null ( ) )
432- . output ( )
433- {
434- Ok ( output) if output. status . success ( ) => output,
449+ let output = match run_with_timeout (
450+ Command :: new ( "wsl.exe" )
451+ . args ( [ "-l" , "-q" ] )
452+ . creation_flags ( CREATE_NO_WINDOW )
453+ . stdout ( std:: process:: Stdio :: piped ( ) )
454+ . stderr ( std:: process:: Stdio :: null ( ) ) ,
455+ Duration :: from_secs ( 5 ) ,
456+ ) {
457+ Some ( output) if output. status . success ( ) => output,
435458 _ => return Vec :: new ( ) ,
436459 } ;
437460
0 commit comments