Skip to content

v0.3.0

Latest

Choose a tag to compare

@xingyuli xingyuli released this 04 Jul 09:36

Features

  • Add .blfrc config support — Support loading config file path from ~/.blfrc in the home directory. Allows specifying one or more config files (absolute, tilde, or home-relative paths), combining multiple configs with fast conflict detection. Eliminates the need to pass --config repeatedly and enables running blf from any directory.
  • Add upgrade subcommand — New blf upgrade command that auto-detects the install method (uv tool or pipx) from sys.executable and runs the correct upgrade command automatically. Supports --dry-run to preview the command without executing.
  • Implement reverse link command — New blf revlink create <path> command converts an existing file or directory in the current working directory into a managed symlink. Uses a copy-checksum-replace approach to ensure data integrity, adds the path to .git/info/exclude, and registers it in the config subpath list.
  • Add revlink restore subcommand — New blf revlink restore <path> is the exact inverse of revlink create. Dissolves a managed symlink back into a real file/directory by copying from the managed location, verifying MD5 integrity, then removing the managed copy and cleaning up .git/info/exclude and config subpath entries.

Usability

  • Add CLI completion for project names — Shell auto-completion now works for managed project names in blf link check and blf link sync. Reads available project names from the config and provides them as tab-completion candidates across bash, zsh, and fish.

Code Quality

  • Refactor non-CLI enums out of options.py — Moved SyncStatus from options.py into sync_state.py, where it belongs alongside the copy strategy state it describes. options.py now exclusively contains user-facing CLI option enums, making the module's contract precise and self-documenting.
  • Refactor load_config_projects return type — Replaced the anonymous tuple[dict, Path] return with a named ConfigLoadResult dataclass. The config_file field now holds the resolved path to the config file itself (not its parent directory), eliminating fragile basename reconstruction at all three call sites in cli.py.