# osx-backup

Outil CLI interactif (Python 3.13, `uv run osx-backup`) qui sauvegarde un Mac de développeur vers un disque externe et le réinstalle sur un Mac vierge. Miroir « latest », pas de snapshots.

## Documents de référence

- Spec validée : `docs/superpowers/specs/2026-09-03-osx-backup-design.md`
- Plan d'implémentation : `docs/superpowers/plans/2026-09-03-osx-backup.md`

Lire la spec avant toute modification de comportement. Le plan est la source des signatures entre modules.

## Commandes

```bash
uv sync                      # installe deps + groupe dev
uv run pytest                # tests
uv run ruff check . && uv run ruff format .
uv run osx-backup map        # inventaire, aucune écriture
uv run osx-backup backup --dry-run --all --dest /tmp/x
```

## Architecture

- `src/osx_backup/cli.py` : commandes `map`, `backup`, `restore` (typer).
- `src/osx_backup/modules/` : un module par domaine (brew, mise, uv, dotfiles, secrets, claude, editors, github, documents, postgres, docker, apps). Chaque module implémente `inventory`, `backup`, `restore` et déclare `order` (ordre de restauration).
- `map.toml` : liste blanche des dotfiles ; `secret = true` route l'entrée vers l'archive chiffrée `secrets.tar.age` (pyrage).
- Toute commande externe passe par `ctx.runner` (injectable : `RealRunner`, `RecordingRunner` pour les tests, `DryRunRunner`).
- Toute écriture dans `$HOME` au restore passe par `ctx.place`, qui déplace l'existant vers `~/.osx-backup-pre-restore/<ts>/`.

## Contraintes machine

- Le `rsync` système est openrsync : les modules github/documents exigent le rsync Homebrew (`brew install rsync`).
- Les hooks git bloquent les commits hors Conventional Commits et les commits sur `main`. Faire `git add` puis `git commit -m "..."` dans deux appels séparés, jamais de heredoc dans la même commande.

## Workflow

Branches `feature/<nom>` depuis `dev`, merge `--ff-only` dans `dev`, suppression de la branche. `main` uniquement sur demande explicite de l'utilisateur. TDD : test rouge, implémentation, test vert, commit.
