77 "fmt"
88 "os"
99 "os/exec"
10+ "os/signal"
1011 "path/filepath"
1112 "runtime"
1213 "strings"
@@ -332,7 +333,7 @@ func renderUnixEnv(shareInfo *api.SharePublicInfo, config *studio.GPUEnvConfig,
332333 out .Println ()
333334 out .Printf (" Connection URL: %s\n " , shareInfo .ConnectionURL )
334335 out .Printf (" Hardware: %s\n " , shareInfo .HardwareVendor )
335- out .Printf (" Log Path: %s\n " , config . LogPath )
336+ out .Printf (" Log Path: %s\n " , envResult . EnvVars [ "TF_LOG_PATH" ] )
336337 out .Println ()
337338 }
338339
@@ -448,10 +449,26 @@ func launchGPUShell(config *studio.GPUEnvConfig, envResult *studio.GPUEnvResult,
448449
449450 // Print GPU environment banner
450451 fmt .Printf ("\n %s GPU environment activated %s\n " , styles ().Success .Render ("✓" ), styles ().Muted .Render ("(type 'exit' to deactivate)" ))
451- fmt .Println ()
452+ fmt .Printf ("%s\n \n " , styles ().Muted .Render ("Ctrl+C interrupts the current command, not the GPU environment." ))
453+
454+ // Ignore SIGINT in parent process - let the child shell handle Ctrl+C naturally.
455+ // Without this, Ctrl+C kills both the parent ggo process and the child shell,
456+ // causing the entire rGPU environment to exit unexpectedly.
457+ sigChan := make (chan os.Signal , 1 )
458+ signal .Notify (sigChan , os .Interrupt )
459+ go func () {
460+ for range sigChan {
461+ // Intentionally ignored - the child shell handles Ctrl+C
462+ }
463+ }()
452464
453465 // Run the shell and wait for it to exit
454- return cmd .Run ()
466+ err := cmd .Run ()
467+
468+ // Restore default signal handling after shell exits
469+ signal .Stop (sigChan )
470+
471+ return err
455472}
456473
457474// styles returns the default TUI styles
@@ -837,7 +854,7 @@ func renderWindowsEnv(shareInfo *api.SharePublicInfo, config *studio.GPUEnvConfi
837854 out .Println ()
838855 out .Printf (" Connection URL: %s\n " , shareInfo .ConnectionURL )
839856 out .Printf (" Hardware: %s\n " , shareInfo .HardwareVendor )
840- out .Printf (" Log Path: %s\n " , config . LogPath )
857+ out .Printf (" Log Path: %s\n " , envResult . EnvVars [ "TF_LOG_PATH" ] )
841858 out .Println ()
842859 }
843860
@@ -990,12 +1007,13 @@ func launchGPUShellWindows(config *studio.GPUEnvConfig, envResult *studio.GPUEnv
9901007 env = append (env , fmt .Sprintf ("%s=%s" , k , v ))
9911008 }
9921009
993- // Add libs path to PATH - libs directory contains only .dll files
1010+ // Add libs path and GPU bin directory to PATH
1011+ binDir := getGPUBinDir ()
9941012 existingPath := os .Getenv ("PATH" )
9951013 if existingPath != "" {
996- env = append (env , fmt .Sprintf ("PATH=%s;%s" , libsPath , existingPath ))
1014+ env = append (env , fmt .Sprintf ("PATH=%s;%s;%s" , binDir , libsPath , existingPath ))
9971015 } else {
998- env = append (env , fmt .Sprintf ("PATH=%s" , libsPath ))
1016+ env = append (env , fmt .Sprintf ("PATH=%s;%s" , binDir , libsPath ))
9991017 }
10001018
10011019 // Set CUDA_PATH - point to libs directory
@@ -1008,16 +1026,33 @@ func launchGPUShellWindows(config *studio.GPUEnvConfig, envResult *studio.GPUEnv
10081026 // Mark as GPU Go activated
10091027 env = append (env , "_GGO_ACTIVE=1" )
10101028 env = append (env , fmt .Sprintf ("_GGO_LIBS_PATH=%s" , libsPath ))
1029+ env = append (env , fmt .Sprintf ("_GGO_BIN_PATH=%s" , binDir ))
10111030
10121031 cmd .Env = env
10131032
10141033 // Print GPU environment banner
10151034 styles := tui .DefaultStyles ()
10161035 fmt .Printf ("\n %s GPU environment activated %s\n " , styles .Success .Render ("✓" ), styles .Muted .Render ("(type 'exit' to deactivate)" ))
1017- fmt .Println ()
1036+ fmt .Printf ("%s\n \n " , styles .Muted .Render ("Ctrl+C interrupts the current command, not the GPU environment." ))
1037+
1038+ // Ignore SIGINT (Ctrl+C) in parent process - let the child shell handle it.
1039+ // On Windows, CTRL_C_EVENT is sent to all processes in the console.
1040+ // Without this, the Go runtime terminates ggo on Ctrl+C, killing the shell.
1041+ sigChan := make (chan os.Signal , 1 )
1042+ signal .Notify (sigChan , os .Interrupt )
1043+ go func () {
1044+ for range sigChan {
1045+ // Intentionally ignored - the child shell handles Ctrl+C
1046+ }
1047+ }()
10181048
10191049 // Run the shell and wait for it to exit
1020- return cmd .Run ()
1050+ err := cmd .Run ()
1051+
1052+ // Restore default signal handling after shell exits
1053+ signal .Stop (sigChan )
1054+
1055+ return err
10211056}
10221057
10231058// tempEnvResultWindows implements Renderable for Windows temporary env setup
@@ -1132,7 +1167,7 @@ func setupLongTermUnix(shareInfo *api.SharePublicInfo, config *studio.GPUEnvConf
11321167 out .Printf (" Config directory: %s\n " , outputDir )
11331168 out .Printf (" Connection URL: %s\n " , shareInfo .ConnectionURL )
11341169 out .Printf (" Hardware: %s\n " , shareInfo .HardwareVendor )
1135- out .Printf (" Log Path: %s\n " , config . LogPath )
1170+ out .Printf (" Log Path: %s\n " , envResult . EnvVars [ "TF_LOG_PATH" ] )
11361171 out .Println ()
11371172 }
11381173
@@ -1265,7 +1300,7 @@ func setupLongTermWindows(shareInfo *api.SharePublicInfo, config *studio.GPUEnvC
12651300 out .Printf (" Config directory: %s\n " , outputDir )
12661301 out .Printf (" Connection URL: %s\n " , shareInfo .ConnectionURL )
12671302 out .Printf (" Hardware: %s\n " , shareInfo .HardwareVendor )
1268- out .Printf (" Log Path: %s\n " , config . LogPath )
1303+ out .Printf (" Log Path: %s\n " , envResult . EnvVars [ "TF_LOG_PATH" ] )
12691304 out .Println ()
12701305 }
12711306
0 commit comments