fix(shell): the loader written into ~/.profile could never be removed, by anything - #14
Open
fcreme wants to merge 1 commit into
Open
fix(shell): the loader written into ~/.profile could never be removed, by anything#14fcreme wants to merge 1 commit into
fcreme wants to merge 1 commit into
Conversation
…, by anything
shell-init registers into ~/.profile in two branches -- the one where
.bashrc exists alongside it, and the nothing-existed fallback -- because
in that layout it is the only file the login shell will read, and
creating a .bash_profile would shadow a file already in use.
~/.profile is deliberately NOT a registration candidate: it is sh's file
rather than bash's, and writing to it unasked would reach past the shells
this tool claims. Removal walked that same registration list, so it never
looked at the file init had just written to.
shell-init -> added ~/.bashrc, added ~/.profile
shell-remove -> "removed from ~/.bashrc"
"Open a new tab to get your original prompt back."
left in ~/.profile: 1
The message is false in the way that matters: ~/.profile is the file the
login shell reads, so the loader the user was told was gone is the only
one still running. After `tstyles uninstall` it points at a data root
that has just been deleted -- on every login shell, permanently, with
nothing left on the machine able to remove it and nothing that ever said
it was there.
Removal now walks Get-ShellRcRemovalCandidate: the registration list plus
~/.profile. Write the narrow set, sweep the wide one. Unregister-ShellLoader
returns 'none' for a file with no block and never creates a file that does
not exist, so the extra entry is free wherever it was never used.
The test meant to guarantee this asserted that shell-init and uninstall
both MENTION Get-ShellRcCandidate. Sharing a helper name is not symmetry,
and that lint passed for the entire life of the bug. Replaced with a
behavioural round-trip over six rc layouts: run init, run remove, count
the markers left on disk, and separately assert the user's own lines came
back. Checked by reverting the fix -- the ~/.profile-only and
.bashrc+~/.profile layouts both go red, naming the file left behind.
Found by an adversarial audit (3 independent verifiers, 0 refutations).
Note this predates the ~/.profile registration added for #9 in 0.8.21:
the .bashrc-exists branch has orphaned the same way since it was written,
and the round-trip covers both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc4mE7gSHoux5wL6VEo59S
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.
Found by an adversarial audit — two independent lenses reported it, 0 of 3 verifiers refuted, and I reproduced it before fixing.
The bug
shell-initregisters into~/.profilein two branches, because in that layout it is the only file the login shell will read and creating a.bash_profilewould shadow a file already in use.~/.profileis deliberately not a registration candidate — it is sh's file rather than bash's, and writing to it unasked would reach past the shells this tool claims. Removal walked that same registration list, so it never looked at the file init had just written to:The message is false in the way that matters:
~/.profileis the file the login shell reads, so the loader the user was told was gone is the only one still running. Aftertstyles uninstallit points at a data root that has just been deleted — on every login shell, permanently, with nothing left on the machine able to remove it and nothing that ever said it was there.The fix
Removal walks
Get-ShellRcRemovalCandidate: the registration list plus~/.profile. Write the narrow set, sweep the wide one.Unregister-ShellLoaderreturns'none'for a file with no block and never creates a file that does not exist, so the extra entry is free wherever it was never used.The test that should have caught it
There was one. It asserted that
shell-initanduninstallboth mentionGet-ShellRcCandidate:Sharing a helper name is not symmetry, and that lint passed for the entire life of the bug. Replaced with a behavioural round-trip over six rc layouts — run init, run remove, count the markers left on disk — plus a separate assertion that the user's own lines came back. Mutation-checked: reverting the fix turns the
~/.profile-only and.bashrc + ~/.profilelayouts red, naming the file left behind.Provenance
This predates the
~/.profileregistration I added for #9 in 0.8.21. I verified that:51f401ealready had one$dotProfileregistration — the.bashrc-exists branch — and it orphans identically. My change added a second route into an existing hole, and I should have tested the inverse when I made it. The round-trip covers both branches.Verification
1435 passed, 0 failed. Shell tests write to real rc paths, so I checksummed
~/.zshrc,~/.bashrc,~/.bash_profileand~/.profilebefore and after — unchanged.🤖 Generated with Claude Code
https://claude.ai/code/session_01Fc4mE7gSHoux5wL6VEo59S