Repository navigation
UI Consistency: 1 issue found
apps/web/src/components/ThreadTerminalDrawer.tsx — the new confirmCloseTerminal guard is installed only at the drawer's click sites, while the same close action remains reachable without confirmation through the terminal.close keybinding in ChatView (and closePanelTerminal). The buttons' own tooltips advertise that shortcut (Close Terminal (⌘W)), so one labeled action now behaves two different ways depending on entry point. Suggested fix: put the confirmation in the owner of the action (closeTerminal / closePanelTerminal in ChatView, or a shared helper) and keep the drawer buttons wired to plain onCloseTerminal.
Secondary note on the same block: the if (!localApi) fallback is unreachable in the renderer (readLocalApi() returns undefined only without window); when no ConfirmDialogHost is mounted, dialogs.confirm resolves false and the close is silently dropped instead of falling through.
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 reviewed: the four changed hunks in apps/web/src/components/ThreadTerminalDrawer.tsx and their directly affected consumers.
Checks performed:
- Confirm-dialog convention:
localApi.dialogs.confirm(...)with a question-first multi-line message and{ variant: "destructive" }matches the existing pattern (ChatViewcheckpoint revert,Sidebar,useThreadActions) and renders through the sharedConfirmDialogHost→AlertDialogprimitive, so no primitive-reconstruction or styling finding. - Message parsing:
resolveConfirmDialogCopysplits the leading?line into the title and renders the remainder withwhitespace-pre-line, so the joined message renders correctly. - No Tailwind, CSS ownership, theme-variant, scroll/mask, or layout changes are present in the diff.
- Entry-point audit for terminal close: drawer toolbar button (updated), split-pane header button (updated), sidebar tab close button (updated),
onSessionExited(correctly left unconfirmed),terminal.closekeybinding inChatView(not confirmed),closePanelTerminal(not confirmed).
One inline review comment was posted on the new confirmCloseTerminal callback.
🔍 Agent activity — 1 tool call
💭 I'm checking the diff that adds a confirm dialog via localApi, and want to verify it matches existing patterns for shared dialog primitives, imports like useCallback, and helper usage before looking at the actual file. I want to check the surrounding code for terminalLabelById and getTerminalLabel to see if there's a hoisting issue with the confirm callback or a missing dependency on getTerminalLabel, so I'll look at that context more closely. I should check whether all onCloseTerminal call sites were updated consistently—only 3 were changed, but there might be other paths like keyboard shortcuts, middle-click on tabs, or context menu actions that still close terminals without confirmation. I'll grep for onCloseTerminal usages across the file to verify. I notice a bare button with no children around line 1691-1696, so I want to check the surrounding context. There's also a keyboard shortcut for closing the terminal that seems handled elsewhere in the parent component rather than here, which could be a consistency concern but is likely outside the scope of these changed lines. I'll look at the sidebar tab region around 1640-1710 to verify. I'm checking whether TerminalActionButton is a separate reconstruction of Button, though it's unchanged in this PR. I also want to verify whether closing via a keyboard shortcut bypasses the confirmation dialog, creating an inconsistency with the click path — I need to trace where that keybinding handler actually lives, likely in a parent component. A few smaller things stand out too: the getTerminalLabel fallback looks redundant since terminalLabelById already handles it, the promise chain uses
.thenwithout a.catchwhile other call sites prefer await/try-catch, and there's no guard against double-clicking close while the dialog is already open. I also notice other parts of the codebase sometimes use a different label-fallback pattern for the terminal drawer, which is a minor inconsistency worth flagging. I notice the keybinding handler in ChatView.tsx calls closeTerminal directly without confirmation, while the button with the same label shows a confirmation dialog — creating an inconsistency between the shortcut and click paths. I'm weighing whether this counts as an in-scope UI consistency issue since ChatView.tsx is a directly affected consumer of the changed behavior. Now I want to check whether localApi.dialogs.confirm is a native Electron dialog versus checking if there's an in-app AlertDialog/ConfirmDialog primitive under components/ui that should be preferred instead. This confirms it's using the app's shared confirm dialog, consistent with the rest of the codebase. I want to check confirmDialog.ts to understand its contract—whether it returns a promise, what happens if no host is mounted, and whether it supports rendering multi-line messages since the code joins lines with newlines. If the dialog renders the message in a plain paragraph without preserving whitespace, those newlines would collapse visually. I should check other call sites like LegacySidebar, ChatView, and useThreadActions to see how they handle formatting multi-line messages. The message format logic looks fine, and edge cases like question marks in terminal labels shouldn't cause issues since the title detection just checks the first line. I'm now thinking about whether focus gets properly restored after the dialog closes, since this is the terminal drawer context where the terminal itself had focus. Actually, I think I've spotted the real bug:readLocalApi()in the browser always returns a valid api object, so the!localApiguard only ever triggers during SSR, not when the ConfirmDialogHost simply hasn't mounted yet. That means if the host isn't mounted — during tests, embedded surfaces, or before mount —localApi.dialogs.confirmwould resolve to undefined/false and clicking Close would silently do nothing instead of closing the terminal. I want to check how other call sites, like the SidebarUpdatePill, handle this same local-api-not-ready scenario to see if there's a more robust pattern being used elsewhere. That popover trigger issue is pre-existing, not part of this diff. Since there are no styling changes here, the real findings have to be about behavioral consistency — preserving interaction semantics and keeping the smallest durable contract rather than visual stuff. I want to check how destructive confirm messages are phrased elsewhere, like in ChatView and Sidebar, to see if the tone of "Close terminal 'X'?" matches existing conventions. The message style matches existing conventions well. But I notice the keyboard shortcutterminal.closebypasses the new confirmation dialog entirely, while the button tooltip advertises "Close Terminal (⌘W)" as if they're the same action — so the same labeled action behaves inconsistently depending on how it's invoked. This is a real consistency finding since it's a directly affected call site within the review's scope. I should also check whether other terminal-close UI elements, like tabs in RightPanelTabs, close immediately without confirmation while the drawer now requires it — that would be another cross-app inconsistency worth flagging. Let me trace whereclosePanelTerminalgets passed and used elsewhere in ChatView. The panel mode likely reuses the same drawer component for confirmation, keeping behavior consistent, while the right-panel tab strip's close button triggers a different action—closing the whole surface rather than just the terminal. I want to confirm the keyboard shortcut actually maps to the same terminal-close action as the button, not a separate bypass path. Tracing further, the button now confirms but the ⌘W shortcut doesn't, even though both share the same tooltip label and shortcut hint—this looks like a genuine interaction inconsistency introduced by the PR, worth flagging as an inline comment since preserving interaction semantics is explicitly in scope. I'm also considering whether thedialogs.confirmfallback silently resolving to false when no ConfirmDialogHost is mounted matters in practice—checking whether ConfirmDialogHost is actually mounted at the root for all web routes, which it appears to be. Other minor candidates I'm weighing: double-clicking close could queue two confirmations and trigger onCloseTerminal twice (a pre-existing pattern elsewhere, so low priority), and whether opening a confirm dialog while a hover-triggered tooltip popover is still open causes any visual conflict—probably not significant enough to flag. I'm now deciding how to frame the final verdict. The instructions suggest reporting "All clear" only if there are no findings, but the actual output needs to follow the JSON schema, so I'll state success/failure there directly rather than literally writing "All clear." Before settling, I want to check if there's a stronger issue I'm missing. hover doesn't reveal it via focus-visible either, so this is pre-existing and only marginally relevant to the patch. I'm also checking whether confirm flows are conventionally handled in the action hooks versus presentational components — it looks mixed across the codebase, so that's not a strong signal either. I want to trace how ThreadTerminalDrawer's onCloseTerminal prop is wired to see if the patch changes that path meaningfully. The real issue is that placing confirmation logic inside the drawer only covers the drawer's click paths, while ChatView invokes the same close action from a keybinding — so the confirmation should live in ChatView's closeTerminal/closePanelTerminal callback so every entry point shares it consistently. I'll leave an inline comment on the new useCallback block noting that the confirmation only guards the drawer's click sites, while the ⌘W keybinding and closePanelTerminal still bypass it. I'm also considering briefly flagging the deadif (!localApi)branch — readLocalApi() only returns undefined when window is undefined, and if the themed host isn't mounted, confirm() silently resolves false and drops the close. It's minor since the host is mounted at root, so I'll just mention it as a secondary note rather than a separate comment. Now I need to pin down the exact diff line numbers for the inline comment, targeting the new lines around 1276–1298 on the right side. I should also double-check the keyboard shortcut claim — confirming the close-terminal handler lives in the global keydown listener in ChatView, around lines 4806-4816, and checking whether there's a separate context-menu entry for closing a terminal via right-click. Weighing whether this inconsistency between the button and shortcut behavior counts as a failing finding: it's not technically a regression since the shortcut still works as before, but it is a real consistency gap introduced by the change. Given the explicit guidance that consistency issues can fail the check, I'm leaning toward marking this as a failure rather than defaulting to success. The tooltip literally advertises "Close Terminal (⌘W)" on a button that now confirms before closing, while the actual ⌘W shortcut skips that confirmation — that's a concrete, verifiable mismatch, so I'll mark this as a failure and post the review.
1. modify_pr — One consistency finding on the new close-terminal confirmation: the guard lives in the drawer's click handlers only, so the keyboard entry point for the same action still closes instantly. Details inline.
Agent Credits: 87 credits