@@ -1005,9 +1005,9 @@ func openCodex(t *terminal.Terminal, sshAlias string, path string, codexArgs []s
10051005 codexCmd = "codex " + strings .Join (codexArgs , " " )
10061006 }
10071007
1008- // Prepend installer paths, set env if needed, then attach-or-create tmux session
1008+ // Source nvm, prepend installer paths, set env if needed, then attach-or-create tmux session
10091009 remoteScript := fmt .Sprintf (
1010- `export PATH="$HOME/.local/bin:$HOME/.npm-global/bin:$PATH"; %stmux has-session -t %s 2>/dev/null && tmux attach-session -t %s || (cd %s && tmux new-session -s %s %s)` ,
1010+ `export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; export PATH="$HOME/.local/bin:$HOME/.npm-global/bin:$PATH"; %stmux has-session -t %s 2>/dev/null && tmux attach-session -t %s || (cd %s && tmux new-session -s %s %s)` ,
10111011 envExport , sessionName , sessionName , shellescape .Quote (path ), sessionName , shellescape .Quote (codexCmd ),
10121012 )
10131013
@@ -1053,7 +1053,7 @@ func isRemoteCodexAuthenticated(sshAlias string) bool {
10531053
10541054func ensureCodexInstalled (t * terminal.Terminal , sshAlias string ) error {
10551055 checkCmd := fmt .Sprintf (
1056- "ssh %s 'export PATH=\" $HOME/.local/bin:$HOME/.npm-global/bin:$PATH\" ; which codex >/dev/null 2>&1'" ,
1056+ "ssh %s 'export NVM_DIR= \" $HOME/.nvm \" ; [ -s \" $NVM_DIR/nvm.sh \" ] && . \" $NVM_DIR/nvm.sh \" ; export PATH=\" $HOME/.local/bin:$HOME/.npm-global/bin:$PATH\" ; which codex >/dev/null 2>&1'" ,
10571057 sshAlias ,
10581058 )
10591059 checkExec := exec .Command ("bash" , "-c" , checkCmd ) // #nosec G204
@@ -1062,16 +1062,26 @@ func ensureCodexInstalled(t *terminal.Terminal, sshAlias string) error {
10621062 return nil // already installed
10631063 }
10641064
1065- // Verify npm is available on remote before attempting install
1065+ // Ensure npm is available on remote, install Node.js via nvm if needed
10661066 npmCheck := fmt .Sprintf ("ssh %s 'which npm >/dev/null 2>&1'" , sshAlias )
10671067 npmExec := exec .Command ("bash" , "-c" , npmCheck ) // #nosec G204
10681068 if npmErr := npmExec .Run (); npmErr != nil {
1069- return fmt .Errorf ("failed to install Codex: npm is not installed on the remote instance. Please install Node.js/npm first" )
1069+ t .Vprintf ("npm not found on remote instance, installing Node.js via nvm...\n " )
1070+ nvmInstall := fmt .Sprintf (
1071+ "ssh %s 'curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && export NVM_DIR=\" $HOME/.nvm\" && . \" $NVM_DIR/nvm.sh\" && nvm install --lts'" ,
1072+ sshAlias ,
1073+ )
1074+ nvmExec := exec .Command ("bash" , "-c" , nvmInstall ) // #nosec G204
1075+ output , err := nvmExec .CombinedOutput ()
1076+ if err != nil {
1077+ return fmt .Errorf ("failed to install Node.js via nvm: %s\n %s" , err , string (output ))
1078+ }
1079+ t .Vprintf ("%s" , t .Green ("Node.js installed successfully\n " ))
10701080 }
10711081
10721082 t .Vprintf ("Installing Codex CLI on remote instance...\n " )
10731083
1074- installCmd := fmt .Sprintf ("ssh %s 'npm install -g @openai/codex 2>/dev/null || sudo npm install -g @openai/codex'" , sshAlias )
1084+ installCmd := fmt .Sprintf ("ssh %s 'export NVM_DIR= \" $HOME/.nvm \" ; [ -s \" $NVM_DIR/nvm.sh \" ] && . \" $NVM_DIR/nvm.sh \" ; npm install -g @openai/codex 2>/dev/null || sudo npm install -g @openai/codex'" , sshAlias )
10751085 installExec := exec .Command ("bash" , "-c" , installCmd ) // #nosec G204
10761086 output , err := installExec .CombinedOutput ()
10771087 if err != nil {
0 commit comments