mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-09 19:49:58 +00:00
fix: stop creating ~/.bash_profile — was destroying system PATH (#1258)
On Ubuntu/Debian, ~/.bash_profile doesn't exist by default. When bash starts as a login shell (bash -l), it sources the FIRST file it finds from: ~/.bash_profile, ~/.bash_login, ~/.profile. Since only ~/.profile exists, that's what gets sourced — and ~/.profile sets up the standard PATH (/usr/bin, /bin, etc.) and sources ~/.bashrc. Our inject_env_vars_* functions and _finalize_claude_install were writing to ~/.bash_profile and ~/.zprofile (either via touch+append or via for-loop over all rc files). Creating ~/.bash_profile caused bash -l to source it INSTEAD of ~/.profile, completely losing the standard PATH setup. After deployment, even basic commands like `ls` would fail. Fix: Only write to ~/.profile, ~/.bashrc, ~/.zshrc across all clouds (shared, fly, sprite). These are the standard files that work correctly on all Linux distros without breaking the shell initialization chain. Co-authored-by: lab <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
99b21e2797
commit
46e6f46008
4 changed files with 21 additions and 24 deletions
|
|
@ -156,7 +156,7 @@ inject_env_vars_local mock_upload mock_run "MY_KEY=my_value"
|
|||
// inject_env_vars_local does NOT pass server_ip - upload gets (local_path, remote_path)
|
||||
expect(result.stdout).toContain("UPLOAD_ARGS:");
|
||||
expect(result.stdout).toContain("/tmp/env_config");
|
||||
expect(result.stdout).toContain("for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >>");
|
||||
expect(result.stdout).toContain("cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc");
|
||||
});
|
||||
|
||||
it("should generate correct env config content", () => {
|
||||
|
|
|
|||
|
|
@ -378,9 +378,10 @@ inject_env_vars_fly() {
|
|||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
# Upload and append to .profile, .bash_profile, .bashrc, and .zshrc
|
||||
# Upload and append to .profile, .bashrc, .zshrc ONLY.
|
||||
# CRITICAL: Do NOT write to ~/.bash_profile or ~/.zprofile — see shared/common.sh.
|
||||
upload_file "${env_temp}" "/tmp/env_config"
|
||||
run_server "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >> \"\$rc\"; done && rm /tmp/env_config"
|
||||
run_server "cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Note: temp file will be cleaned up by trap handler
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1090,10 +1090,10 @@ inject_env_vars_ssh() {
|
|||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
# Upload and append to .profile, .bash_profile, .bashrc, and .zshrc
|
||||
# bash -l sources the FIRST of ~/.bash_profile, ~/.bash_login, ~/.profile
|
||||
# Append to .profile, .bashrc, .zshrc only — NEVER create ~/.bash_profile
|
||||
# (creating it makes bash -l skip ~/.profile, destroying the standard PATH)
|
||||
"${upload_func}" "${server_ip}" "${env_temp}" "/tmp/env_config"
|
||||
"${run_func}" "${server_ip}" "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >> \"\$rc\"; done && rm /tmp/env_config"
|
||||
"${run_func}" "${server_ip}" "cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Note: temp file will be cleaned up by trap handler
|
||||
|
||||
|
|
@ -1119,9 +1119,9 @@ inject_env_vars_local() {
|
|||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
# Upload and append to .profile, .bash_profile, .bashrc, and .zshrc
|
||||
# Append to .profile, .bashrc, .zshrc only — never .bash_profile
|
||||
"${upload_func}" "${env_temp}" "/tmp/env_config"
|
||||
"${run_func}" "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >> \"\$rc\"; done && rm /tmp/env_config"
|
||||
"${run_func}" "cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Note: temp file will be cleaned up by trap handler
|
||||
|
||||
|
|
@ -1264,20 +1264,15 @@ install_claude_code() {
|
|||
# Include fnm paths so node is found even in non-interactive SSH sessions
|
||||
local claude_path='export PATH=$HOME/.claude/local/bin:$HOME/.local/bin:$HOME/.bun/bin:$HOME/.local/share/fnm:$PATH; if command -v fnm >/dev/null 2>&1; then eval "$(fnm env)"; fi'
|
||||
|
||||
# Finalize installation: set up shell integration (PATH, completions)
|
||||
# Persists claude and fnm PATH entries to .profile/.bashrc/.zshrc
|
||||
# Finalize: set up shell integration and persist PATH to .profile/.bashrc/.zshrc.
|
||||
# NEVER write to ~/.bash_profile — creating it breaks Ubuntu's login shell chain.
|
||||
_finalize_claude_install() {
|
||||
log_step "Setting up Claude Code shell integration..."
|
||||
${run_cb} "${claude_path} && claude install --force" >/dev/null 2>&1 || true
|
||||
# Write claude PATH to all shell configs so login shells find the binary.
|
||||
# .bashrc has a non-interactive guard that skips appended exports when
|
||||
# run via `ssh host "cmd"` or `bash -lc`, so .profile is essential.
|
||||
# Write claude PATH to all shell configs so login shells find the binary.
|
||||
# bash -l sources the FIRST of ~/.bash_profile, ~/.bash_login, ~/.profile
|
||||
# so we must write to all of them to be safe.
|
||||
${run_cb} "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do touch \"\$rc\"; grep -q '.claude/local/bin' \"\$rc\" 2>/dev/null || printf '\\n# Claude Code PATH\\nexport PATH=\"\$HOME/.claude/local/bin:\$HOME/.local/bin:\$HOME/.bun/bin:\$PATH\"\\n' >> \"\$rc\"; done" >/dev/null 2>&1 || true
|
||||
# Ensure fnm bootstrap is in all shell configs so new shells can find node
|
||||
${run_cb} "if command -v fnm >/dev/null 2>&1 || test -d \$HOME/.local/share/fnm; then for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do grep -q 'fnm env' \"\$rc\" 2>/dev/null || printf '\\n# fnm (node version manager)\\nexport PATH=\"\$HOME/.local/share/fnm:\$PATH\"\\nif command -v fnm >/dev/null 2>&1; then eval \"\\\$(fnm env)\"; fi\\n' >> \"\$rc\"; done; fi" >/dev/null 2>&1 || true
|
||||
# Write claude PATH to .profile (login shells), .bashrc, .zshrc
|
||||
${run_cb} "for rc in ~/.profile ~/.bashrc ~/.zshrc; do grep -q '.claude/local/bin' \"\$rc\" 2>/dev/null || printf '\\n# Claude Code PATH\\nexport PATH=\"\$HOME/.claude/local/bin:\$HOME/.local/bin:\$HOME/.bun/bin:\$PATH\"\\n' >> \"\$rc\"; done" >/dev/null 2>&1 || true
|
||||
# Ensure fnm bootstrap is in shell configs so new shells can find node
|
||||
${run_cb} "if command -v fnm >/dev/null 2>&1 || test -d \$HOME/.local/share/fnm; then for rc in ~/.profile ~/.bashrc ~/.zshrc; do grep -q 'fnm env' \"\$rc\" 2>/dev/null || printf '\\n# fnm (node version manager)\\nexport PATH=\"\$HOME/.local/share/fnm:\$PATH\"\\nif command -v fnm >/dev/null 2>&1; then eval \"\\\$(fnm env)\"; fi\\n' >> \"\$rc\"; done; fi" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
# Already installed?
|
||||
|
|
@ -1381,7 +1376,7 @@ inject_env_vars_cb() {
|
|||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
${upload_cb} "${env_temp}" "/tmp/env_config"
|
||||
${run_cb} "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >> \"\$rc\"; done && rm /tmp/env_config"
|
||||
${run_cb} "cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
offer_github_auth "${run_cb}"
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ setup_shell_environment() {
|
|||
export PATH="${HOME}/.bun/bin:/.sprite/languages/bun/bin:${PATH}"
|
||||
EOF
|
||||
|
||||
# Upload and append to shell configs
|
||||
sprite exec -s "${sprite_name}" -file "${path_temp}:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.zprofile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config"
|
||||
# Upload and append to .profile and .zshrc ONLY (not .zprofile)
|
||||
sprite exec -s "${sprite_name}" -file "${path_temp}:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.profile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config"
|
||||
|
||||
# Switch bash to zsh
|
||||
local bash_temp
|
||||
|
|
@ -209,8 +209,9 @@ inject_env_vars_sprite() {
|
|||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
# Upload and append to .profile, .bash_profile, .bashrc, and .zshrc using sprite exec
|
||||
sprite exec -s "${sprite_name}" -file "${env_temp}:/tmp/env_config" -- bash -c "for rc in ~/.profile ~/.bash_profile ~/.bashrc ~/.zshrc ~/.zprofile; do cat /tmp/env_config >> \"\$rc\"; done && rm /tmp/env_config"
|
||||
# Upload and append to .profile, .bashrc, .zshrc ONLY using sprite exec.
|
||||
# CRITICAL: Do NOT write to ~/.bash_profile or ~/.zprofile — see shared/common.sh.
|
||||
sprite exec -s "${sprite_name}" -file "${env_temp}:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.profile && cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
trap - EXIT
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue