Repository navigation
fix(cua): stabilize native window previews and Windows app identity - #16975
juliusmarminge wants to merge 8 commits into
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
…d hosts (#4877) The embedded host builds the daemon environment from an allowlist, and CUA_DRIVER_RS_ENABLE_WAYLAND was not on it. A host such as an Electron app could never turn on the native Wayland backend: the opt-in was dropped silently. Allow it, and test inheritance, an explicit host opt-in, and an explicit opt-out winning over an inherited opt-in. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.); credited in THIRD_PARTY_NOTICES.md. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ing (#4880) The libei worker replied as soon as input requests were flushed to the socket. A flush is not delivery: the caller's focus guard could restore the user's window while the compositor still had the input queued, and the input then landed in the wrong app. After each input command, send ei_connection.sync and reply only when EIS answers its callback, which it does after processing every earlier request. If no answer comes within 5 s, fail with "delivery is unknown" instead of reporting success. WaitReady and failed commands reply immediately as before. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…s v10) On GNOME Wayland, window screenshots were crops of the Shell stage. GetRects proves a window's geometry, not that nothing covers it, so a covered window's screenshot showed the app on top. The WinRects helper gains two additive methods: - CaptureWindow(id, pid), API 9: snapshot the window's own actor with paint_to_content. Covered windows keep their content, nothing is activated, and a 1x1 transparent clone keeps Mutter painting a fully covered window for 4 s after the last capture. Refused while locked, for minimized windows, and above 32 MiB. - CaptureWindowPreview(id, pid, max), API 10: the same capture, downscaled on the GPU, returning the full-size dimensions too. The driver uses CaptureWindow whenever the attested helper reports API 9 or newer, and then never falls back to a stage crop. Older helpers keep the stage crop, so users who have not reinstalled the helper keep window screenshots. A screenshot-only get_window_state with a size cap uses CaptureWindowPreview (falling back to the full capture on older helpers), and GNOME's per-capture Creation Time PNG chunk is removed so unchanged preview frames compare equal. list_windows asks a verified GNOME helper first instead of probing other compositor protocols. Versioning: the UUID stays winrects@cua. One UUID means one installed copy per user; two UUIDs would race for org.cua.WinRects. API numbers 9 and 10 match T3 Code's bundled helper exactly, so either copy serves both drivers. install.sh and both cua-driver installers no longer downgrade a newer installed helper (install.sh --force still does). The helper README documents the rules and the version table. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). The stage-crop fallback for older helpers and the no-downgrade installers are new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er (#4879) * perf(cua-driver): reuse one session-bus connection for the GNOME helper Every WinRects call spawned a gdbus subprocess, and owner attestation alone makes three D-Bus calls before the real one. A live preview pays that on every frame. Replace the subprocess with one zbus connection on a dedicated single-thread Tokio runtime, so callers inside or outside Tokio can block on it without nesting runtimes. Bodies are typed on the wire, and replies keep the textual shape the existing parsers read (GetRects now arrives as raw JSON, which also avoids gdbus quoting). A timeout or transport error drops the connection and the next call reconnects; a mutation is never replayed. An error reply, such as no helper on the bus, keeps the connection. T3 Code measured window capture going from 381 ms to 58 ms with this transport. Ported from their Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.); the reply-versus-transport split is new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cua-driver): cover GetRects titles gdbus would have escaped Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cua-driver): strict GetRects parsing and run the bus test in Nix Parse the typed GetRects reply as raw JSON instead of slicing a bracket span, and reuse that parser for focus. Salvaged from #4809, including the malformed-snapshot fixtures and the Nix dbus check input. Co-authored-by: injaneity <44902825+injaneity@users.noreply.github.com> * test(cua-driver): start the private test bus from its own config dbus-daemon --session needs the system session.conf, which the Nix build sandbox lacks; the daemon then exits without an address. Write a minimal session config listening in a temp dir instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Louis Grenard <1731544+louistiti@users.noreply.github.com>
…s v10) On GNOME Wayland, window screenshots were crops of the Shell stage. GetRects proves a window's geometry, not that nothing covers it, so a covered window's screenshot showed the app on top. The WinRects helper gains two additive methods: - CaptureWindow(id, pid), API 9: snapshot the window's own actor with paint_to_content. Covered windows keep their content, nothing is activated, and a 1x1 transparent clone keeps Mutter painting a fully covered window for 4 s after the last capture. Refused while locked, for minimized windows, and above 32 MiB. - CaptureWindowPreview(id, pid, max), API 10: the same capture, downscaled on the GPU, returning the full-size dimensions too. The driver uses CaptureWindow whenever the attested helper reports API 9 or newer, and then never falls back to a stage crop. Older helpers keep the stage crop, so users who have not reinstalled the helper keep window screenshots. A screenshot-only get_window_state with a size cap uses CaptureWindowPreview (falling back to the full capture on older helpers), and GNOME's per-capture Creation Time PNG chunk is removed so unchanged preview frames compare equal. list_windows asks a verified GNOME helper first instead of probing other compositor protocols. Versioning: the UUID stays winrects@cua. One UUID means one installed copy per user; two UUIDs would race for org.cua.WinRects. API numbers 9 and 10 match T3 Code's bundled helper exactly, so either copy serves both drivers. install.sh and both cua-driver installers no longer downgrade a newer installed helper (install.sh --force still does). The helper README documents the rules and the version table. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). The stage-crop fallback for older helpers and the no-downgrade installers are new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s v10) (#4882) * feat(cua-driver): capture GNOME windows from their own actor (WinRects v10) On GNOME Wayland, window screenshots were crops of the Shell stage. GetRects proves a window's geometry, not that nothing covers it, so a covered window's screenshot showed the app on top. The WinRects helper gains two additive methods: - CaptureWindow(id, pid), API 9: snapshot the window's own actor with paint_to_content. Covered windows keep their content, nothing is activated, and a 1x1 transparent clone keeps Mutter painting a fully covered window for 4 s after the last capture. Refused while locked, for minimized windows, and above 32 MiB. - CaptureWindowPreview(id, pid, max), API 10: the same capture, downscaled on the GPU, returning the full-size dimensions too. The driver uses CaptureWindow whenever the attested helper reports API 9 or newer, and then never falls back to a stage crop. Older helpers keep the stage crop, so users who have not reinstalled the helper keep window screenshots. A screenshot-only get_window_state with a size cap uses CaptureWindowPreview (falling back to the full capture on older helpers), and GNOME's per-capture Creation Time PNG chunk is removed so unchanged preview frames compare equal. list_windows asks a verified GNOME helper first instead of probing other compositor protocols. Versioning: the UUID stays winrects@cua. One UUID means one installed copy per user; two UUIDs would race for org.cua.WinRects. API numbers 9 and 10 match T3 Code's bundled helper exactly, so either copy serves both drivers. install.sh and both cua-driver installers no longer downgrade a newer installed helper (install.sh --force still does). The helper README documents the rules and the version table. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). The stage-crop fallback for older helpers and the no-downgrade installers are new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cua-driver): credit every T3 Code Linux port in THIRD_PARTY_NOTICES Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…d hosts (trycua#4877) The embedded host builds the daemon environment from an allowlist, and CUA_DRIVER_RS_ENABLE_WAYLAND was not on it. A host such as an Electron app could never turn on the native Wayland backend: the opt-in was dropped silently. Allow it, and test inheritance, an explicit host opt-in, and an explicit opt-out winning over an inherited opt-in. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.); credited in THIRD_PARTY_NOTICES.md. Backported to the 0.34 release line from main (cherry picked from commit 07cbc6c). Conflict: THIRD_PARTY_NOTICES.md keeps the 0.34.0 table and adds only the T3 Code row (the QuickJS/rquickjs rows and trope-cua wording belong to 0.35 changes not in this line). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing (trycua#4880) The libei worker replied as soon as input requests were flushed to the socket. A flush is not delivery: the caller's focus guard could restore the user's window while the compositor still had the input queued, and the input then landed in the wrong app. After each input command, send ei_connection.sync and reply only when EIS answers its callback, which it does after processing every earlier request. If no answer comes within 5 s, fail with "delivery is unknown" instead of reporting success. WaitReady and failed commands reply immediately as before. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). Backported to the 0.34 release line from main (cherry picked from commit 9487b0f). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er (trycua#4879) * perf(cua-driver): reuse one session-bus connection for the GNOME helper Every WinRects call spawned a gdbus subprocess, and owner attestation alone makes three D-Bus calls before the real one. A live preview pays that on every frame. Replace the subprocess with one zbus connection on a dedicated single-thread Tokio runtime, so callers inside or outside Tokio can block on it without nesting runtimes. Bodies are typed on the wire, and replies keep the textual shape the existing parsers read (GetRects now arrives as raw JSON, which also avoids gdbus quoting). A timeout or transport error drops the connection and the next call reconnects; a mutation is never replayed. An error reply, such as no helper on the bus, keeps the connection. T3 Code measured window capture going from 381 ms to 58 ms with this transport. Ported from their Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.); the reply-versus-transport split is new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cua-driver): cover GetRects titles gdbus would have escaped Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cua-driver): strict GetRects parsing and run the bus test in Nix Parse the typed GetRects reply as raw JSON instead of slicing a bracket span, and reuse that parser for focus. Salvaged from trycua#4809, including the malformed-snapshot fixtures and the Nix dbus check input. Co-authored-by: injaneity <44902825+injaneity@users.noreply.github.com> * test(cua-driver): start the private test bus from its own config dbus-daemon --session needs the system session.conf, which the Nix build sandbox lacks; the daemon then exits without an address. Write a minimal session config listening in a temp dir instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Backported to the 0.34 release line from main (cherry picked from commit 48cc491). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s v10) (trycua#4882) * feat(cua-driver): capture GNOME windows from their own actor (WinRects v10) On GNOME Wayland, window screenshots were crops of the Shell stage. GetRects proves a window's geometry, not that nothing covers it, so a covered window's screenshot showed the app on top. The WinRects helper gains two additive methods: - CaptureWindow(id, pid), API 9: snapshot the window's own actor with paint_to_content. Covered windows keep their content, nothing is activated, and a 1x1 transparent clone keeps Mutter painting a fully covered window for 4 s after the last capture. Refused while locked, for minimized windows, and above 32 MiB. - CaptureWindowPreview(id, pid, max), API 10: the same capture, downscaled on the GPU, returning the full-size dimensions too. The driver uses CaptureWindow whenever the attested helper reports API 9 or newer, and then never falls back to a stage crop. Older helpers keep the stage crop, so users who have not reinstalled the helper keep window screenshots. A screenshot-only get_window_state with a size cap uses CaptureWindowPreview (falling back to the full capture on older helpers), and GNOME's per-capture Creation Time PNG chunk is removed so unchanged preview frames compare equal. list_windows asks a verified GNOME helper first instead of probing other compositor protocols. Versioning: the UUID stays winrects@cua. One UUID means one installed copy per user; two UUIDs would race for org.cua.WinRects. API numbers 9 and 10 match T3 Code's bundled helper exactly, so either copy serves both drivers. install.sh and both cua-driver installers no longer downgrade a newer installed helper (install.sh --force still does). The helper README documents the rules and the version table. Ported from T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.). The stage-crop fallback for older helpers and the no-downgrade installers are new here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cua-driver): credit every T3 Code Linux port in THIRD_PARTY_NOTICES Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Backported to the 0.34 release line from main (cherry picked from commit 78212ad). Conflict: THIRD_PARTY_NOTICES.md keeps the 0.34.0 table; the T3 Code row now lists every ported file, as on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ews (trycua#4881) Backport of trycua#4881 to the 0.34 release line, reworked for the 0.34.0 code. `display_only:true` on get_window_state (with include_accessibility_tree:false) returns the window's pixels and metadata but publishes, refreshes and removes no snapshot and registers no action capture, so a preview polling the window several times a second (T3 Code's picture-in-picture) no longer stales the agent's element tokens or pixel frame. It maps onto the existing internal observation-only read on macOS, Windows and Linux; on macOS it also skips the background_input probe. The contract matches T3 Code's Linux patch to Cua Driver 0.34.0 (pingdotgg/t3code#16975, MIT, Copyright (c) 2026 T3 Tools Inc.) word for word: the schema property T3 feature-detects, the refusal `display_only requires include_accessibility_tree:false`, and the `display_only` / `frame_note` result fields. The typed contract (cua-driver-contract) and the UniFFI surface are unchanged. Differences from main's trycua#4881: - main keeps the helper in cua_driver_core::window_state_view, which does not exist on 0.34; here it is cua_driver_core::display_only with the same strings and functions, and each backend adds the property to its own schema. - Not backported: plain screenshot-only reads refreshing the current snapshot in place on Windows and Linux (refresh_screenshot_for_session is 0.35 snapshot-store code). On 0.34.x a plain screenshot-only read behaves as in 0.34.0; display_only is the side-effect-free read. - No tool-description or skill text changes; the property's description carries the contract. cli-specs and the generated reference page gain the property (macOS regenerated from the native dump). (cherry picked from commit 4cbd096, with conflicts reworked) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
815c9fa to
ef78271
Compare
ef78271 to
ba8c7e3
Compare
Cua Driver 0.34.1 includes our Linux fixes: the Wayland opt-in reaches embedded hosts, GNOME windows are captured from their own actor (WinRects API 10), the GNOME helper reuses one session-bus connection, and get_window_state accepts display_only. Linux packaging now bundles the published release like macOS and Windows, so the source patch, the native build script, SDK library replacement, the Linux CLI bundle lookup, and the extra CI toolchain are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ba8c7e3 to
5261335
Compare
|
terminal-preview-24 feasibility: blocked on the native stack and final-driver verification; no changes pushed. The actual head is The final native pass needs:
Keep the app-mention feature separate from the preview lifecycle fix when the parent stack is ready. Capture the outstanding before/after recording against the final installed driver. No duplicate with #18217 or #8469 was found. |
Computer-use PiP could show unrelated desktop pixels after a failed window capture, flash while replacing images, and remain open after a turn ended. Capture now stays bound to the selected window, retries transient failures, decodes replacement frames before painting them to a persistent canvas, and dismisses the computer preview when the turn settles. Windows packaged apps now retain their own names and native icons instead of appearing as ApplicationFrameHost.exe.
The subscriber-driven loop caps active capture at 4 FPS, leaves idle time after slow captures, suppresses identical frames, and drops static-window polling to 1 FPS after three unchanged captures. A changed frame restores the normal rate; renewed motion can take up to one second to detect. Drivers advertising
display_onlyuse an observation-only capture that skips action-registry PNG decoding and snapshot replacement. Older drivers keep the typed screenshot path. No SDK ABI change is required.Stacked on #16532.
Windows integration
Window identities are keyed by PID and window handle, so Calculator and Settings remain distinct when Windows hosts them in one process. PiP captions and icons travel with the captured frame, display-only inspections do not redirect the preview, and native icons resolve packaged-app AUMIDs through their manifests. Duplicate detection includes app identity as well as image bytes and window metadata.
The temporary Cua Driver 0.34.1 CREATE_NO_WINDOW source patch and regression test are included in
patches/cua-driver-0.34.1-windows-console.patch.T3CODE_CUA_DRIVER_SDK_LIBRARYoptionally stages a locally rebuilt Windows SDK DLL into both the desktop host and server sidecar. This override is opt-in; normal release builds still use the published SDK.Windows test build 9007 was exercised interactively: Calculator operations stayed in the background, its name/icon matched the preview, closing it showed an unavailable state, and Theo confirmed no flashing. After integration with the newer stack head: 133 focused tests pass, one is skipped, and two packaging tests fail identically on the parent commit (Linux cargo executable lookup on Windows and the cross-architecture native probe). Server/web typechecks and targeted lint pass. The combined stack has not received another packaged interactive pass.
Windows integration by GPT-6.1-Sol through the Codex harness.
Cua Driver 0.34.1
The native Linux fixes this PR used to carry as a source patch shipped upstream in Cua Driver 0.34.1 (trycua/cua#4895): the Wayland opt-in reaches embedded hosts, GNOME windows are captured from their own actor with compositor downscaling (WinRects API 10), the GNOME helper reuses one session-bus connection, GNOME's changing PNG
Creation Timechunk is stripped, andget_window_stateacceptsdisplay_onlyon Linux, macOS, and Windows with the same schema, refusal, and response fields.The stack now pins 0.34.1 from #16527 (SDK, platform packages, and the release checksum table), and this PR packages Linux like macOS and Windows: the published driver archive is bundled, and the SDK's native library comes from npm. The source patch,
scripts/build-cua-linux.sh, SDK library replacement, the Linux CLI's bundled-driver lookup, and the extra Rust toolchain and X11/Wayland dev packages in CI are removed.One piece of the old patch is not upstream: it hid GNOME's stage-wide agent cursor during window-targeted actions and after each action ended. With 0.34.1 that cursor follows upstream behavior.
Evidence from the patched build
Measured on the patched 0.34.0 build, whose native changes 0.34.1 now ships. 0.34.1 itself has not been reprofiled.
A covered Helium window benchmark measured median native capture at 61.1 ms normally versus 38.5 ms display-only (19 measured calls per mode after warmup). For static content, normal 4 FPS capture used 14.3% driver CPU / 13.3% GNOME CPU / 4.8% device GPU busy; display-only adaptive polling used 1.8% / 6.9% / 3.8%, with 23 captures and one changed frame over 20.8 seconds. For animated content, capture stayed at 4 FPS while driver CPU fell from 14.8% to 6.1%. The persistent D-Bus transport reduced median native capture from 381 ms to 58 ms and raised capture rate from 1.29 to 4 FPS.
Installed build 2757: the covered Helium window appears correctly in the actual PiP. A 30-second static run captured 33 frames and averaged 2.65% device GPU busy and 41.7% tracked CPU (down from 7.3%/62.2% on 2755); an animated run captured 119 frames (3.96/sec) at 9.48% GPU and 62.4% CPU (down from 13.0%/72.9%). Closing PiP stopped capture completely: zero calls for 20 seconds. Tracked CPU includes T3 processes, GNOME, Cua, and Helium; one core = 100%.
Validation
apps/server/src/cua,apps/desktop/src/cua,packages/shared/src/cuaDriverHostOptions.test.ts,scripts/build-desktop-artifact.test.ts,scripts/lib/cli-external-packages.test.ts: 166 pass. The one failure, "skips the primary native probe for cross-architecture Windows payloads", also fails onmain.linux-x86_64-binaryarchive matches the pinned SHA-256 on Linux x64, reportscua-driver 0.34.1, and itsget_window_stateschema advertisesdisplay_onlywith the description our capability probe matches.Still draft: before/after video evidence is outstanding, and an installed 0.34.1 build has not been exercised on GNOME.
Implemented with GPT-6 Astra through the Codex harness; the 0.34.1 bump and removal of the source patch by Claude Opus 5.5 through Claude Code.
🤖 Generated with Claude Code
Application mentions
The composer can now find installed applications from the selected environment when typing @, including Helium on Windows. Selections retain the environment and launch identity, render as native app chips, and tell providers to resolve the current window before interacting. The inventory uses Cua Driver's cross-platform listApps API and stays disabled when Computer Use is off. Native icons retain a fallback until the image loads and when loading fails.
Validation: 184 focused tests pass across app inventory, reference projection, composer editing, icon loading, and authorization. Server/web typechecks passed. Windows build 9009 was exercised with an @helium mention: the provider received the correct executable and environment, launched Helium, navigated releases and discussions, and closed its test window. macOS/Linux inventory behavior has fixture coverage but has not been exercised interactively.
Application mentions implemented with GPT-6.1-Sol through the Codex harness.