Repository navigation
fix(cli): install bash completions without hiding ~/.profile - #27
Merged
Merged
Conversation
On macOS, `fctl completions --install` (which the installer runs) always added its block to ~/.bash_profile, creating the file when it was missing. Bash login shells read only the first of ~/.bash_profile, ~/.bash_login and ~/.profile that exists, so a new ~/.bash_profile quietly stopped bash from reading the ~/.profile people already had. The block now goes at the end of the file bash reads at login, and a new ~/.profile when there is none, since that hides nothing. sh, dash and ksh read ~/.profile too and stop at bash syntax, so the block loads the script only under bash, in an `if` that leaves `. ~/.profile && ...` working in other shells. Writing the block also replaced any startup file it could not read as UTF-8 (a Latin-1 comment was enough) with the block alone. It now reads bytes, appends, and stops with an error if it cannot read the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On macOS,
fctl completions --install(the installer runs it) always added its block to~/.bash_profileand created that file if it was missing. Bash login shells, which Terminal and iTerm2 start, read only the first of~/.bash_profile,~/.bash_loginand~/.profilethat exists. If someone's settings were in~/.profile, the new~/.bash_profilestopped bash from reading them, and their shell lost its PATH and the rest until they deleted the file.What changed
~/.bash_profile,~/.bash_loginand~/.profilethat exists. If none of them exists, it creates~/.profile. That file comes last in bash's order, so creating it can't hide anything. zsh, fish and bash on Linux (~/.bashrc) behave as before.sh,dashandkshlogin shells also read~/.profile, and the generated script is bash syntax. When dash sources it, it stops with a syntax error, anddash -l -c …exits without running its command. The block now checks$BASH_VERSION. It usesif … firather than an&&chain, so. ~/.profile && cmdstill succeeds in other shells. Blocks that are already installed keep working, and the marker still stops a second copy.read_to_string(..).unwrap_or_default()and wrote it back withfs::write. If a file wasn't valid UTF-8 (one Latin-1 byte in a comment is enough), it was read as empty and replaced with the fctl block alone. Now it reads bytes, appends, and returns an error rather than writing over a file it can't read. This change points it at people's long-lived~/.profile, so I fixed this in the same pull request.docs/cli.mdnow says where the block goes.Not in this change
~/.profile(or~/.bash_login) but no~/.bash_profile, still has the~/.bash_profileit created. This change doesn't touch it:--installfinds the marker there and does nothing. The fix is to delete~/.bash_profileif it holds only the fctl block, then runfctl completions --installagain. 0.1.2 shipped on 2026-10-17, so few people can have the stray file, and I didn't add code that deletes files in people's home directories.fctl self updatecould do it if we want that.~/.zshrcor~/.bashrc. Its PATH hint for bash appends to~/.profile, which bash login shells skip when~/.bash_profileexists (on macOS, that's every new terminal). I couldn't reach that repository from this session.How I verified it
crates/fctl/src/cmd/completions.rs. They fail on the old code and pass now. They cover the reported case (an existing~/.profilegets the block at its end and no~/.bash_profileappears) and bash's order (.bash_profile, then.bash_login, then.profile). They also cover a new~/.profilewhen there is none, the guarded block, and a Latin-1~/.bashrckeeping its bytes. They runinstallagainst a temporary home directory withmacosset either way. I had no Mac, so the macOS file choice is tested only there.HOMEwith a Latin-1~/.bashrc, and its contents were replaced by the block. The new binary appends and leaves the original bytes as they were. A second run adds nothing.~/.profileand tried real shells.bash -lreads the profile and registerscomplete -F _fctl fctl.dash -lreads the profile without errors, andsh -c 'set -eu; . ~/.profile && …'succeeds. With the old block in the same place,dash -ldied on a syntax error. An interactivebash -iloads the completions from~/.bashrc.cargo fmt --all --check,cargo clippy --workspace --all-targets -D warnings, the wasm clippy forfctl-controlandcargo test --workspaceall pass.cargo xtask check --quickstopped atnpm ci, because this sandbox can't fetch the private@hyperstructure/designpackage. The web app is unchanged.Session: https://app.fctl.sh/s/ses_01M56488710JJ92CYMX0N7GPMB
🤖 Generated with Claude Code