Old clones made before the default-branch rename sit on a local `master`
whose upstream still points at the deleted refs/heads/master, so both a
bare `git pull` and `_run_upgrade()`'s `git checkout main` failed on stale
clones. The updater now fetches origin first, checks out main via
`git checkout -B main origin/main`, repairs the upstream to origin/main,
and pulls explicitly with `git pull origin main` so it never consults the
dangling branch.*.merge config. Existing dirty-branch and detached-HEAD
guards are unchanged.
Adds tests covering the renamed-clone migration and the fetch-failure bail.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Symptom: user on the `dev` branch upgrading from v2.10.0 to v2.10.2 saw
the "Upgrade now? [y/N]" prompt fire on every restart. Accepting it ran
the install pipeline successfully but the next launch re-prompted the
same way.
Root cause: release tags in this repo live on main-side merge commits
(e.g. v2.10.2 is on the `Merge branch 'dev' into main` commit). That
commit is *downstream* of `dev`, so walking back from dev's HEAD,
setuptools-scm finds only v2.10.0 and reports e.g. `2.10.0.post1.dev9`.
After hate_crack/__init__.py strips the post/dev suffix, `__version__`
is `"2.10.0"` again. check_for_updates() sees `2.10.2 > 2.10.0` and
re-prompts forever. `git pull` on dev is a no-op because dev is fully
synced — the tag just isn't on the branch.
Fix: _run_upgrade() now detects the current branch via `git symbolic-ref
--short HEAD`. If it's not `main`, refuse to clobber uncommitted work
(git status --porcelain), then `git checkout main` before running the
existing pull/install pipeline. The release-tagged commit is now on
HEAD, setuptools-scm regenerates a clean version, and the loop ends.
Safety guards:
- Uncommitted changes: bail with manual-steps message (exit 1) — no
git checkout attempted.
- main checked out in another worktree: surface git's stderr and bail
with manual instructions.
- Detached HEAD (symbolic-ref returncode != 0): skip the switch and
let the existing flow run — no regression for users on a tag.
- Already on main: skip the switch block; behavior unchanged.
Tests (tests/test_version_check.py):
- test_run_upgrade_switches_from_dev_to_main_then_upgrades
- test_run_upgrade_bails_when_non_main_branch_is_dirty
- test_run_upgrade_bails_when_checkout_main_fails
- test_run_upgrade_skips_switch_when_already_on_main
- test_run_upgrade_skips_switch_on_detached_head
Four pre-existing tests updated to thread an extra branch_proc mock
through the new symbolic-ref subprocess call.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
_run_upgrade now runs `git pull && git fetch --tags && make install`
instead of the bespoke _install_system_deps function. make install is
idempotent, handles all platforms, installs system deps (transmission-
daemon, p7zip), rebuilds the Python package, and updates the CLI shim.
Remove the now-unnecessary uv binary pre-check (make install locates
it) and its stale test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add _install_system_deps() called by _run_upgrade() after a successful
git pull. Installs transmission-daemon (Linux) or transmission-cli brew
formula (macOS) so users who upgrade don't need to re-run make install
manually. Also corrects _run_upgrade to exit 1 on failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When running as root or via sudo, /root/.local/bin may not be in PATH.
Use shutil.which with fallback to ~/.local/bin/uv, and fail clearly
if uv can't be found.
uv's PEP 517 build isolation copies source to a temp dir without .git,
so setuptools-scm can't determine the version and falls back to the
existing _version.py. Forcing --reinstall-package hate_crack makes uv
rebuild from source in the actual repo dir (editable mode) where git
is accessible, so the correct version is generated.
Refactors the upgrade logic into _run_upgrade() so it can be called
both from the startup version check prompt and directly via --update,
bypassing the version comparison entirely.
When a newer release is found, prompt the user to upgrade in-place.
Resolves the git repo root via `git rev-parse --show-toplevel` before
running `git pull && make clean && make && make install`, so the upgrade
works correctly whether hate_crack is run from source or installed into
site-packages. Ctrl-C and EOF at the prompt continue normally.
- Add optional startup version check against GitHub releases (check_for_updates config option)
- Add packaging dependency for version comparison
- Fix PassGPT OOM on MPS by capping batch size to 64 and setting memory watermark limits
- Fix PassGPT output having spaces between every character
- Hide PassGPT menu item (17) unless torch/transformers are installed
- Fix mypy errors in passgpt_generate.py with type: ignore comments
- Update README with version check docs, optional ML deps section, and PassGPT CLI options
- Add test_version_check.py with 8 tests covering update check behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>