@@ -1116,9 +1116,9 @@ func openCodex(t *terminal.Terminal, sshAlias string, path string, codexArgs []s
11161116 codexCmd = "codex " + strings .Join (codexArgs , " " )
11171117 }
11181118
1119- // Prepend installer paths, set env if needed, then attach-or-create tmux session
1119+ // Source nvm, prepend installer paths, set env if needed, then attach-or-create tmux session
11201120 remoteScript := fmt .Sprintf (
1121- `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)` ,
1121+ `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)` ,
11221122 envExport , sessionName , sessionName , shellescape .Quote (path ), sessionName , shellescape .Quote (codexCmd ),
11231123 )
11241124
@@ -1164,7 +1164,7 @@ func isRemoteCodexAuthenticated(sshAlias string) bool {
11641164
11651165func ensureCodexInstalled (t * terminal.Terminal , sshAlias string ) error {
11661166 checkCmd := fmt .Sprintf (
1167- "ssh %s 'export PATH=\" $HOME/.local/bin:$HOME/.npm-global/bin:$PATH\" ; which codex >/dev/null 2>&1'" ,
1167+ "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'" ,
11681168 sshAlias ,
11691169 )
11701170 checkExec := exec .Command ("bash" , "-c" , checkCmd ) // #nosec G204
@@ -1173,16 +1173,26 @@ func ensureCodexInstalled(t *terminal.Terminal, sshAlias string) error {
11731173 return nil // already installed
11741174 }
11751175
1176- // Verify npm is available on remote before attempting install
1176+ // Ensure npm is available on remote, install Node.js via nvm if needed
11771177 npmCheck := fmt .Sprintf ("ssh %s 'which npm >/dev/null 2>&1'" , sshAlias )
11781178 npmExec := exec .Command ("bash" , "-c" , npmCheck ) // #nosec G204
11791179 if npmErr := npmExec .Run (); npmErr != nil {
1180- return fmt .Errorf ("failed to install Codex: npm is not installed on the remote instance. Please install Node.js/npm first" )
1180+ t .Vprintf ("npm not found on remote instance, installing Node.js via nvm...\n " )
1181+ nvmInstall := fmt .Sprintf (
1182+ "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'" ,
1183+ sshAlias ,
1184+ )
1185+ nvmExec := exec .Command ("bash" , "-c" , nvmInstall ) // #nosec G204
1186+ output , err := nvmExec .CombinedOutput ()
1187+ if err != nil {
1188+ return fmt .Errorf ("failed to install Node.js via nvm: %s\n %s" , err , string (output ))
1189+ }
1190+ t .Vprintf ("%s" , t .Green ("Node.js installed successfully\n " ))
11811191 }
11821192
11831193 t .Vprintf ("Installing Codex CLI on remote instance...\n " )
11841194
1185- installCmd := fmt .Sprintf ("ssh %s 'npm install -g @openai/codex 2>/dev/null || sudo npm install -g @openai/codex'" , sshAlias )
1195+ 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 )
11861196 installExec := exec .Command ("bash" , "-c" , installCmd ) // #nosec G204
11871197 output , err := installExec .CombinedOutput ()
11881198 if err != nil {
0 commit comments