ssr mackup scan now only suggests NEW files — it never overwrites an
existing ssr-*.cfg. Once created, the file belongs to the user who
edits it directly in ~/.mackup/ to customise which paths are backed up.
- _ssr_mackup_write_cfg: returns early if file already exists
- scan: drops UPD logic; only shows NEW suggestions
- _ssr_mackup_resolve_paths: removed SSR_MACKUP_SELECTIVE_PATHS support
(ssr.conf config variable removed — edit the cfg files instead)
- Scan output: hints to edit files directly after creation
Co-authored-by: Cursor <cursoragent@cursor.com>
Docker Desktop checks that ~/.docker is a real directory and rejects it
if it is a symlink (Mackup's default when backing up a whole dir).
Solution: remove .docker from the skip list, add it to curated + selective.
Mackup will symlink only ~/.docker/config.json and ~/.docker/daemon.json —
the directory itself stays a real dir that Docker Desktop can manage.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mackup with engine=file_system already uses symlinks for all backed-up
apps (/Users/osurke/.docker → <cloud>/Mackup/mackup/.docker). The copy PHASE
fails when the source dir contains sockets or dangling symlinks.
For dirs like .claude that have a volatile debug/ subdir, the clean fix
is to list only the stable sub-paths in the Mackup cfg rather than the
whole directory — debug/ is never touched.
_SSR_MACKUP_SELECTIVE: built-in overrides for .claude, .cursor, .codex,
.vscode, .factory — lists only config files (settings.json, CLAUDE.md,
skills, plugins, agents, …), skipping logs/, debug/, etc.
_ssr_mackup_resolve_paths(): resolves the [configuration_files] entries
for a given item using the selective table, falling back to the whole dir.
ssr mackup scan now shows '6 sub-path(s) of .claude/' in the plan
instead of '.claude/' to make the selective behaviour visible.
Configurable via SSR_MACKUP_SELECTIVE_PATHS in ssr.conf.
Co-authored-by: Cursor <cursoragent@cursor.com>
Root cause: Claude Code recreates ~/.claude/debug/latest (a dangling
symlink to the current debug session) almost immediately after it is
deleted. The old cleanup ran once before the retry loop, so any retry
after a 2s sleep would hit a freshly recreated symlink.
Fix: move _ssr_mackup_preclean() inside the retry loop so it runs
immediately before each mackup attempt, leaving no window for apps to
recreate problematic files.
Also remove known transient subdirectories by path before the generic
socket/dangling-link sweep:
.claude/debug .cursor/logs .vscode/logs .npm/_logs
Configurable via SSR_MACKUP_PRECLEAN_PATHS (space-separated, $HOME-relative).
Co-authored-by: Cursor <cursoragent@cursor.com>
Previously ssr-custom cfg generation only checked whether the path was
already in the cloud backup directory. It did not consult Mackup's
~400 built-in app definitions, causing duplicates like ssr-claude.cfg
when Mackup already has a 'claude-code' entry covering .claude.
Changes:
- _ssr_mackup_declared_paths(): parses all built-in *.cfg files from
Mackup's Python package apps/ dir + hand-written ~/.mackup/*.cfg
(excluding our own ssr-*.cfg) into a sorted path set
- generate_custom_cfg now skips any path already in that set
- Stale ssr-*.cfg files that now duplicate a built-in are removed
automatically on the next sync run
Co-authored-by: Cursor <cursoragent@cursor.com>
shutil.copy fails on dangling symlinks with [Errno 2] No such file or
directory (e.g. ~/.claude/debug/latest → missing target).
Pre-backup cleanup now handles two cases:
- Unix sockets (-type s) → Errno 102
- Dangling links (-type l !-e) → Errno 2
Both are ephemeral runtime artefacts that cannot be meaningfully backed up.
Co-authored-by: Cursor <cursoragent@cursor.com>
Each discovered dot-dir now gets its own Mackup app definition:
.claude → ~/.mackup/ssr-claude.cfg
.cursor → ~/.mackup/ssr-cursor.cfg
.config/gh → ~/.mackup/ssr-config-gh.cfg
…
This matches Mackup's own convention, keeps definitions independent,
and makes it easy to add/remove individual apps. The old combined
ssr-custom.cfg is removed automatically on the next sync run.
Files are written idempotently (skipped when content is unchanged).
Co-authored-by: Cursor <cursoragent@cursor.com>
Mackup fails with shutil.Error [Errno 102] when it tries to copy Unix
socket files (e.g. iTerm2's iterm2-daemon-1.socket, sockets/secrets).
Sockets are ephemeral runtime artefacts — they cannot be meaningfully
backed up and are always recreated by the owning app on startup.
Purge all -type s files from $HOME before calling mackup backup.
Co-authored-by: Cursor <cursoragent@cursor.com>
Before each `ssr sync`, scan $HOME for dot-dirs/files not yet present
in the Mackup backup directory and write them into
~/.mackup/ssr-custom.cfg. This covers tools like .claude, .cursor,
.easymcp, .codex, .factory, and any future dot-dir without requiring
the user to write manual Mackup app definitions.
Curated list handles common developer tools; auto-discovery adds the
rest while skipping caches, credential dirs (.ssh, .gnupg, .aws,
.azure) and other volatile state.
Configurable via:
SSR_MACKUP_AUTODISCOVER=true (opt-out with false)
SSR_MACKUP_EXTRA_PATHS="..." (space-separated $HOME-relative paths)
Co-authored-by: Cursor <cursoragent@cursor.com>
- Pre-materialize iCloud stubs before restore (same as backup)
- Report stub count so user knows why it might be slow
- Background watchdog prints '… still running (Ns elapsed)' every 15s
so long iCloud download pauses don't look like a hang
- Report total elapsed time on completion
Co-authored-by: Cursor <cursoragent@cursor.com>
brctl download was removed in macOS Sonoma — the remaining subcommands are
diagnose/log/dump/status/accounts/quota/monitor. Replace the dead call with
a find loop that uses 'open -g <real-path>' to request per-file iCloud
download from the daemon, followed by a 1-second settle pause and the
existing .icloud stub deletion.
Also add -f to mackup restore for consistency with the backup call.
Co-authored-by: Cursor <cursoragent@cursor.com>
- bin/ssr-schedule: use `launchctl bootstrap`/`bootout` (modern API) with
legacy `load -w` fallback. The previous `load -w`-only flow silently
no-op'd on macOS 10.15+ in some configurations, leaving `ssr status`
reporting `inactive` after a successful `ssr schedule on`.
- bin/ssr-status: query the service via `launchctl print`/`list <label>`
for consistent active/inactive detection.
- lib/mackup.sh: pre-materialize iCloud placeholders via `brctl download`
and retry `mackup -f backup` up to three times to dodge the recurring
`OSError [Errno 66] Directory not empty` race between mackup's rmtree
and iCloud's filesystem provider. Soft-fails so the rest of `ssr sync`
still runs even if mackup never settles; logs actionable hints.
Co-authored-by: Cursor <cursoragent@cursor.com>