feat(native): add menu-bar popover and background attention

Ready to merge
FA
17h ago
+5221-171

Summary

Stacked on helper recovery #681. The base is fix/helper-recovery so this diff contains only menu-bar/background-attention changes. Retarget to main after the helper PR merges.

Adds an opt-in menu-bar popover so queries and builds can continue while nixmac is hidden, with retained state and actionable native attention for questions, completion, failures and configuration drift.

The change handles tray/Dock/notification reopening, display positioning, and close/Escape routing through dismissible dialogs and Settings. Active work and unsaved editor contents stay mounted. Explicit dismissal returns keyboard focus to another app; normal-window behavior stays within the existing rollout boundary.

Rollout

Off by default. Enable Developer settings by clicking the version seven times under Settings > General, then choose Developer > Feature flags > Menu bar popover > Popover and fully quit/reopen nixmac.

The flag is a persisted local launch-time override, menu-bar-popover=popover. PostHog does not control it, diagnostics may remain off, and hiding Developer settings does not reset it. Choose Default (control) and restart to return to the normal window.

Review fixes

Close fallback ownership now survives failed, false and unanswered dismissal calls. Only the current native close token can hide the popover, and successful hide retires that token. Overlay-first handling and retained editor state stay intact.

Completed activation ownership now expires after an intervening external build, preserving notifications and external-build state for a later rollback.

Transient launch-mode lookup failures retry without poisoning the cache. Full History restores now notify after finalization succeeds or fails. Failure copy names the failed request or build/restore operation.

Test Plan

  • Popover implementation at cbc6b6146: 1,412 Rust tests passed (14 ignored), 454 frontend tests passed; strict workspace Clippy with codegen, TypeScript and frontend production build passed. Generated oRPC bindings are idempotent.
  • Native close suite on cbc6b6146: Escape/Cmd+W/Close focus handoff and retained prompt; History retention and overlay-first Close; rejected/false/unanswered dismissal fallback; delayed close invalidated by reopen; an 8-second unresponsive WebView and recovery. Tray show/hide also passes from a clean launch.
  • Delayed local-provider success and failure both finish while hidden and retain their result.
  • Full History restore through the UI: mocked activation followed by real Git/SQLite finalization. Success creates the expected restored tree, commit and origin record. An index-lock failure creates no restore commit and retains the error. Both delivered outcome notifications reopen the retained view.
  • Startup retry in a separate instrumented native build: the first mode IPC lookup rejects, the next real backend lookup succeeds 250ms later, and ordinary Escape/Cmd+W work without a native-event override. The application entry module and Rust source are unchanged.
  • Normal-window compatibility: idle Escape preserves the window; Cmd+W closes History first, then hides the window; reopening and resizing work; the popover close API stays inactive.
  • Native 800 x 600 content: a 401-line diff, a 120-section reply and 500 lines of injected build-console fixture data remain scrollable with their actions reachable. Diff/reply scroll positions survive hide/reopen.
  • Positioning on both existing 3008 x 1692 displays. Temporarily removing the test tray item exercises the unavailable-item fallback; reopening remains visible and usable. The tray is restored afterward.
  • Two DeveloperTab DOM snapshots pass. The Evolve baseline drift is inherited from the base: the five-image gallery represents 24 failures also present on #681. No blanket baseline acceptance was applied; full Storybook success is not claimed.
  • Restacked onto helper recovery 9383d7139; all five popover commits are unchanged by range-diff. This includes the reviewed diagnostics fix from #681. The shared helper code and permission panel passed real signed-app Retry/Disable/recovery checks on MacinCloud, plus their regression tests.
  • Ownership follow-up at 012c7e753: all 58 state tests and strict workspace Clippy pass. Regressions cover an intervening external build followed by rollback, pre-completion sampling, unavailable reads and stale success events.
  • CI follow-up at 6cda456b9: macOS build and Linux tests passed, including 1,302 macOS Rust tests (10 ignored), 1,266 Linux Rust tests (3 ignored), 460 frontend tests, strict Clippy, signing, notarization and portability. Evaluate passed. Final Danger validation after the description updates is blocked waiting for an ARC runner; CI maintainers need to inspect runner capacity and dispatch. The earlier Danger run passed. Storybook completed with the same 24 inherited Evolve snapshot failures and a lucide-react error generating Creevey baseline images. The five-image gallery contains only after images; full snapshot success is not claimed.
  • Retarget to main after #681 merges, then verify the resulting diff and checks.

Native scope: isolated debug/e2e app with local fixtures and mocked system activation. Restore bookkeeping is real. The one-failure startup test uses a separate frontend-copy bootstrap; the original cbc6b6146 bundle was preserved and restored. Release signing, real system activation, display disconnection and additional screen sizes are outside this pass.

Standalone Filesystem and the editable NixEditor have no reachable entry point in this build. Their state-retention coverage remains automated; no native presentation claim is made for those surfaces.

Docs

  • No docs update needed for the local developer opt-in; the control explains its restart requirement.

#no-linear