cua-driver: detect & suppress background click side-effects - #1477
Conversation
…ow / focus steal)
Adds WindowChangeDetector — a snapshot/detect/suppress pipeline wired
into ClickTool's AX and pixel paths that handles the case where a
background click causes a cross-app side-effect (e.g. clicking
"Browse UTM Gallery" opens a Safari window and briefly activates it).
## What changes
### WindowChangeDetector (new)
- `snapshot()` captures window set + frontmost pid, then immediately arms
a wildcard `SystemFocusStealPreventer` suppression (targetPid = 0) so
any app that self-activates during the action is squashed before the
first compositor frame.
- `detectChanges()` polls for new layer-0 windows or frontmost changes
during the action window, then ends the suppressor.
- `resultSuffix` appends `🪟 Action opened new window(s): <App> ("<title>").`
to the tool result so the background agent is aware of side-effect
windows — without surfacing the foreground-restore machinery.
- `needsRestore` triggers on new windows even when foregroundChanged is
false (suppressor may have prevented the OS-level steal before it was
observable in the poll loop).
### SystemFocusStealPreventer (extended)
- `handleActivation` now also matches wildcard entries (targetPid = 0),
firing for any pid other than `restoreTo`. Covers side-effect apps
whose pid is unknown at arm time (e.g. Safari launched by UTM).
### ClickTool (wired)
- Both AX-indexed and pixel-click paths call `snapshot()` before the
action and `detectChanges()` / `reRaiseForeground()` after.
## Test
`test_click_opens_new_window.py::TestBrowseUTMGalleryUXGuard`
- FocusMonitorApp is the simulated user foreground (ux_guard sentinel).
- UTM is launched in the background; the agent clicks "Browse UTM Gallery".
- Asserts: Safari window appears, 🪟 notice in result, FocusMonitorApp
remains frontmost, focus-loss count ≤ 1 (one unavoidable reactive tick).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR adds a new side-effect detection and foreground-app restoration mechanism. When a UI click causes cross-app foreground changes or new windows to appear, the driver automatically detects these changes and restores the original foreground app. A wildcard focus-suppression mode prevents affected side-effect apps from stealing focus during the restoration window. ChangesForeground Guard for Click Side-Effects
Sequence DiagramsequenceDiagram
participant Action as User Action
participant ClickTool
participant WCD as WindowChangeDetector
participant Suppression as Focus Suppression
participant App as Original Foreground App
Action->>ClickTool: click UI element
ClickTool->>WCD: snapshot()
WCD->>WCD: capture window IDs & front PID
WCD->>Suppression: beginSuppression(targetPid: 0)
WCD-->>ClickTool: Snapshot armed
ClickTool->>ClickTool: execute AX click action
Note over ClickTool: side-effect: Safari opens
ClickTool->>WCD: detectChanges(snapshot)
loop poll until deadline
WCD->>WCD: detect new windows
WCD->>WCD: check foreground change
end
WCD-->>ClickTool: Changes { newWindows: [Safari], needsRestore: true }
alt needsRestore
ClickTool->>WCD: reRaiseForeground(pid)
WCD->>App: activate()
end
WCD->>Suppression: endSuppression()
ClickTool-->>Action: success + "🪟 new Safari window"
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
ClickTool. When a background click causes a cross-app side-effect (e.g. clicking "Browse UTM Gallery" in UTM opens a Safari window), the detector announces it to the agent via🪟 Action opened new window(s): Safari ("Gallery | UTM").in the tool result.targetPid = 0) that fires for any app activation exceptrestoreTo, covering side-effect apps whose pid is unknown at arm time.The foreground-restore machinery is transparent — the agent only sees the new-window notice, not the re-raise.
How it works
snapshot()captures the window set + frontmost pid, then arms the wildcard suppressor so any app that self-activates during the action is squashed before the first compositor frame.FocusGuard.withFocusSuppressedenvelope).detectChanges()polls 1s for new windows or frontmost changes, then ends the suppressor.reRaiseForeground()is called as a belt-and-suspenders belt and the suffix is appended to the result.Test plan
test_click_opens_new_window.py::TestBrowseUTMGalleryUXGuard🪟notice present in click result, naming SafarididActivateApplicationNotification, not before)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests