## 0.32.5 — Resilience & deadlock fixes

### Fixed

- **State-change beachball**: `projects_update` deadlocked on itself when changing anything other than agent mode (color, pin, tab order, worktree mode, heartbeat toggle). A shadowed `parking_lot::MutexGuard` re-acquired the same non-reentrant mutex on the main thread, wedging the UI and triggering macOS hang reports. Diagnosed from a symbolicated spindump; guard lifetimes restructured so the original guard always drops before re-acquire.
- **Rustls CryptoProvider panic on companion auto-start**: both `aws-lc-rs` (via reqwest) and `ring` (via ngrok) were compiled into the binary, so rustls 0.23 refused to auto-pick and panicked on first TLS use. The panic died inside a tokio task, but cost 20–60 s of retry backoff and filled logs with stack traces. Now installs `aws-lc-rs` explicitly at startup — ngrok tunnel comes up on attempt #1.
- **Hold-across-emit deadlock class**: 14 Tauri commands across focus groups, timer, chat history, and agent presets held `state.db.lock()` while firing `app.emit("sync:*", …)`. Each emit risks re-entering a Rust command from a frontend listener that needs the same guard. Audited all 14 files / 81 lock sites; fixed every offender.
- **Timer stop button acted like pause**: `syncFromEvent` reset `showMemoDialog`/`showCountdown`/`showExtendDialog` on every cross-window status sync, and `broadcast_sync` echoes back to the sender — so `stopTimer`'s own broadcast unmounted the memo dialog the instant it was opened. Dialogs are now per-window UI state and no longer synced.
- **Chat history context menu zombie listeners**: the imperative right-click menu only unbound its `document` `mousedown` listener on outside-click, so clicking a menu button left the listener alive. Every subsequent unrelated mousedown tried to `removeChild` a detached node → `NotFoundError`, one zombie per menu use. Refactored to a shared `closeMenu()` that tears down element + listener in both paths.
