Skip to content

fix(desktop): harden window capture recovery

MacroscopeApp / Macroscope - UI Consistency failed Aug 24, 2026 in 3m 41s

UI Consistency: 1 new finding, 3 unresolved

New finding

  • apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx — the dialog body is a raw div with hand-rolled mx-6 spacing (and mt-6 on DialogFooter) instead of DialogPanel. It loses the panel's ScrollArea (content cannot scroll when the popup hits max-h-full, including the mobile sheet) and the :has([data-slot=dialog-panel]) header/footer padding coordination, so spacing diverges from every other dialog in the app. Inline comment posted.

Unresolved from the previous run (not re-posted)

  • apps/web/src/index.css — global, unlayered .animate-in.fade-in.zoom-in-95 rule overrides Tailwind's layered animation utilities (including motion-reduce:animate-none), against the existing animate-[…]-at-the-owner convention.
  • apps/web/src/components/chat/ChatComposer.tsx — the paired animate-in fade-in zoom-in-95 duration-200 class string uses non-existent utilities; duration-200 sets transition, not animation, duration.
  • apps/web/src/components/settings/WindowCaptureSettings.tsx — the shortcut recorder button lacks data-keybinding-capture, so app-level capture-phase keybinding handlers swallow the keystroke before recordShortcut sees it.

The latest commit (62e75d6, "harden window capture recovery") only changed desktop error typing, bridge capability detection, and the drain loop; none of the previously flagged UI issues were addressed.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Scope examined

In-scope changed files: apps/web/src/components/desktop/WindowCaptureCoordinator.tsx, apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx, apps/web/src/components/settings/WindowCaptureSettings.tsx, apps/web/src/components/settings/SettingsSidebarNav.tsx, apps/web/src/components/settings/settingsSearch.ts, apps/web/src/components/chat/WindowCaptureAttachmentDetails.tsx, apps/web/src/components/chat/ChatComposer.tsx, apps/web/src/components/chat/MessagesTimeline.tsx, apps/web/src/components/CommandPalette.tsx, apps/web/src/lib/desktopWindowCapture.ts, apps/web/src/routes/settings.window-capture.tsx, apps/web/src/index.css.

Checks performed

  • Verified text-secondary-label is a real project token (index.css bridge + theme palette), so WindowCaptureAttachmentDetails uses semantic color correctly.
  • Verified the timeline attachment grid is grid-cols-2, so the new col-span-2 full-width capture card is valid geometry, and the compact/expanded variants only add contextual layout at the call site.
  • Compared WindowCaptureSettings against sibling settings pages: it uses SettingsPageContainer/SettingsSection/SettingsRow, shared Switch, Button, and Kbd; omitting searchableSetting on the "Capture now" action row matches existing practice for non-persisted actions.
  • Surveyed all DialogPopup consumers: every other dialog either uses DialogPanel or explicitly sets data-slot="dialog-panel" on a custom body (AddProviderInstanceDialog), which establishes the contract the onboarding dialog breaks.
  • Reviewed 62e75d6 in full to confirm it introduces no new UI-layer styling or primitive-composition issues (bridge capability gating in CommandPalette, WindowCaptureCoordinator, and WindowCaptureSettings reuses the new getDesktopWindowCaptureBridge helper consistently, with a status string for older bridges).

🔍 Agent activity — 15 tool calls

💭 Comparing against the earlier commit, I see the same unresolved issues remain—the animation CSS rule and duration classes are still there, and WindowCaptureSettings still lacks the data-keybinding-capture attribute—so I shouldn't repost those as new comments. I still need to verify whether any other changes were introduced since that last review.

1. git_tools — 7f97b00..62e75d6

💭 The prior commit was probably force-pushed away, so I should check the PR commits. Since the diff still shows the same code for the three flagged items, I need to confirm the current file states to see if those issues persist and whether any new findings have appeared in the in-scope files at head.

2. github_api_read_only — repos/{owner}/{repo}/pulls/{pull_number}/commits?per_page=100

💭 There's a new commit, 62e75d6, about hardening window capture recovery for the desktop app - I want to look into what changed there.

3. git_tools — 62e75d6

💭 The three previously flagged findings still stand since this commit doesn't address them, but I shouldn't re-post them as duplicates. Looking at the new changes in scope—CommandPalette.tsx, WindowCaptureCoordinator.tsx, WindowCaptureSettings.tsx, and desktopWindowCapture.ts—none of these appear to introduce new UI-consistency violations under the rules. I want to double-check a couple things I haven't fully verified yet: whether WindowCaptureOnboardingDialog's custom mx-6 spacing is a call-site override compared to how other dialogs handle content padding via a shared wrapper, and whether text-secondary-label used in WindowCaptureAttachmentDetails is actually a valid design token in this project. I also notice WindowCaptureSettings uses a title prop inconsistently with SettingsRow compared to other usages, though that's minor. Let me verify the token first.

4. git_tools — secondary-label

💭 I should check the Dialog primitive to see how it handles body padding conventions, so I can properly evaluate whether mx-6 in WindowCaptureOnboardingDialog makes sense.

5. browse_code — apps/web/src/components/ui/dialog.tsx

💭 I'm noticing DialogPopup's padding logic depends on data-slot attributes like dialog-panel and dialog-header/footer, but the onboarding dialog's raw div for the shortcut row doesn't use these slots properly. This means the header's conditional padding reduction won't trigger since there's no dialog-panel present, so it keeps full padding instead of the tighter spacing intended. Body content should really be wrapped in DialogPanel to inherit the correct padding contract and scroll behavior, but the raw mx-6 div with manual mt-6 on the footer bypasses that entirely -- meaning no scroll area protection if content overflows on short viewports. I should check other dialogs in the codebase to confirm this is the standard pattern, and grep for other instances of DialogFooter with manual margin overrides to see how common this workaround is.

6. git_tools — DialogFooter className=

💭 Let me check a representative dialog with a header and body block, like SshPasswordPromptDialog, to see the convention used there.

7. git_tools — DialogPanel

💭 I'm noticing the onboarding dialog breaks convention by using a raw div with manual margins instead of DialogPanel, which means it loses the ScrollArea and coordinated padding that other dialogs get through the :has([data-slot=dialog-panel]) selector logic. The fix is straightforward: swap the raw div for <DialogPanel> and remove the manual mx-6/mt-6 overrides. Let me check the actual file now to pin down exact line numbers.

8. browse_code — apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx

💭 This finding wasn't flagged in prior comments, so it's new and not a duplicate, making it fair to post even though the file itself didn't change in the latest commit. I'm now checking whether it's a genuine regression, since DialogPanel already handles ScrollArea with scroll fade and padding coordination together. Without that shared setup, using a bare div could clip content on short viewports or in mobile sheet mode, and the spacing rhythm shifts too — the header's bottom padding lands directly against the card with no vertical margin, while the footer gets its own top margin plus a border, producing an unusual floating separator with a gap rather than the typical padding-only treatment other dialogs use. That inconsistency in vertical rhythm compared to every other dialog seems like the stronger argument for flagging this, on top of the potential scroll clipping issue. I want to check the popup class definition to confirm whether it applies overflow-hidden or a flex column that would explain the clipping behavior on short viewports.

9. browse_code — apps/web/src/components/ui/dialog-styles.ts

💭 Without overflow-hidden, the popup's content could visually spill past the rounded border since DialogPanel is what actually owns the scroll behavior. I'll leave that as one comment, then check whether WindowCaptureSettings' "Capture now" row uses a supported title prop consistently with other rows that use searchableSetting. Missing that registration would just mean the row isn't findable through settings search, which feels more like a functional nit than a styling inconsistency. Let me check if other rows also omit searchableSetting before deciding whether to flag it.

10. git_tools — searchableSetting|<SettingsRow

💭 I'm checking whether WindowCaptureSettings follows the same SettingsPageContainer/SettingsSection convention as other settings pages, and it does. I also want to verify the shortcut recorder's Button onKeyDown handling matches the existing data-key attribute pattern used elsewhere. The KeybindingsSettings recorder and the new keyframe in index.css are both already flagged. The ChatComposer window-capture card's fixed sizing overriding the thumbnail geometry looks intentional, so that's fine. I still want to confirm MessagesTimeline's col-span-2 usage has a grid parent with at least two columns, so I'm going to look around lines 1010-1060.

11. browse_code — apps/web/src/components/chat/MessagesTimeline.tsx

💭 The grid column spanning looks fine, and the window-capture card's fallback handling when previewUrl is missing seems acceptable too. I'm noting the onboarding dialog body isn't using DialogPanel, and I want to check if other dialogs in the codebase have similar bare-div bodies, like SshPass. I'm confirming SshPasswordPromptDialog does use DialogPanel correctly, so now I want to search all DialogPopup usages to see if any others are missing it too.

12. git_tools — DialogPopup

💭 I want to check whether AddProviderInstanceDialog uses DialogPopup versus DialogPanel, just to confirm the convention is consistent.

13. git_tools — Dialog(Panel|Header|Footer|Popup)

14. browse_code — apps/web/src/components/settings/AddProviderInstanceDialog.tsx

💭 I notice the custom body explicitly sets the dialog-panel slot so the header padding rule applies there, confirming that the onboarding dialog's plain div skips that slot entirely and instead hand-rolls its own margin spacing. Since a full fix would require adding an import plus multiple line changes, it's too multi-hunk for an inline diff, so I'll just describe the recommended fix in the comment: swap the raw div for DialogPanel and remove the redundant mt-6 on the footer. I'll flag this as a new inline finding on the added line, and since there are unresolved findings from before plus this new one, the check should report failure.

15. modify_pr — Window capture UI review: one new finding on WindowCaptureOnboardingDialog (dialog body bypasses the DialogPanel contract). The three findings from the previous run (index.css .animate-in.fade-in.zoom-in-95 global override, the matching ChatComposer class string, and the missing data-keybinding-capture on the shortcut recorder) are unchanged in this head commit and are not re-posted.


Agent Credits: 164 credits