Notifications UX: Jump to Latest Unread + per-tab / per-surface dots + tap deeplinks (#266)
* Add Jump to Latest Unread + per-surface notification dots
Adds ⌘⇧U to jump to the newest unread notification across worktrees,
selecting the worktree + focusing the source surface and marking only
that notification as read; the menu item disables when nothing is
unread. Surfaces now render an orange dot overlay while they have
unread notifications, mirroring the sidebar indicator. System
notifications carry a deeplink payload so tapping one routes through
the existing deeplink handler to land on the exact tab + surface that
posted it.
Closes #244.
* Show unread notification dot on tabs
* Polish notification UX + tighten concurrency and logging
- Tab notification dot now lives in the close-button slot: visible
when the tab is idle and has unread notifications, replaced by the
close X on hover.
- `SystemNotificationClient` delegate methods now run on the main
actor directly, so accessing `onDeeplinkTap` no longer needs a
bridging hop. Added `SupaLogger` breadcrumbs for malformed deeplink
payloads, unresolved surface deeplinks, and stale-worktree jumps.
- `latestUnreadNotificationLocation` now walks each worktree's unread
list newest-first until it finds a focusable surface, so a closed
surface on the newest notification no longer hides older focusable
ones. Logs once when every unread points at a closed surface.
- Collapsed duplicate `tabID(forSurfaceID:)` / `tabId(containing:)`
into a single `tabID(containing:)` on `WorktreeTerminalState`.
- Dropped the `createdAt = Date()` default on
`WorktreeTerminalNotification.init` so production code must pass the
injected clock; tests use `.distantPast`.
- Surface dot now animates via an always-mounted `.opacity`/`.animation`
pair rather than a transition without a driver.
- Added `WorktreeTerminalManagerTests` coverage for cross-worktree
ordering, closed-surface fallback, tab-level unread aggregation, and
`markNotificationRead` targeting a single id.
- Tightened the happy-path jump test to assert exact focus command.
* Tighten notification logging + close tab-dot test gap
- `urlOrWarn` now carries `worktreeID` / `surfaceID` into its warning
so diagnostics correlate to the originating surface.
- Log a debug breadcrumb when `latestUnreadNotificationLocation` skips
a closed surface in favour of an older focusable one, preserving the
"which notification was chosen" trace.
- `jumpToLatestUnread` logs a debug line when invoked with no unread,
so the two no-op branches (menu gated vs stale worktree) are
distinguishable in logs.
- New test covers the cross-worktree tie-break path: worktree A's
newest unread is orphaned, A's older focusable is older than
worktree B's only focusable, B wins.
- `hasUnseenNotificationForTabIDWalksSplitTree` now asserts the first
leaf also lights the tab (previously only the second leaf was
exercised), and drops the `_ = firstLeaf` warning-silencer.
authored by