Skip to content

Commit da31b40

Browse files
committed
fix: auto-install Node.js via nvm when npm is missing for codex
1 parent b64ba41 commit da31b40

1 file changed

Lines changed: 16 additions & 6 deletions

File tree

pkg/cmd/open/open.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

10541054
func 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

Comments
 (0)