Skip to content

Commit 0b7a8f5

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

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
@@ -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

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

Comments
 (0)