-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix(windows): Session-0 hardening + UWP background-launch focus restore #1548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
a9d9c02
fix(windows): doctor COM lifecycle + Session 0 hardening for launch p…
f-trycua 9e91f68
test(windows): parity examples Session-0 aware + #1545 contract
f-trycua 7251e73
feat(serve): Session-0 warning banner on Windows daemon startup
f-trycua 2eb3c4d
docs(parity): update list_apps + launch_app Windows status with live …
f-trycua ac70b94
feat(installed_apps): filter opaque-system-family UWP packages from l…
f-trycua 6f58020
fix(installed_apps): drop Package.IsFramework() probe — hangs in Sess…
f-trycua d5b5821
fix(launch_uwp): claim 'last input' before SetForegroundWindow restore
f-trycua ca95e93
docs(status): update Windows Session-0 status report with final fix list
f-trycua d75a447
docs(status): add good-morning TL;DR with merge one-liner and visual-…
f-trycua f2adb89
docs(faq): add Windows Session-0 troubleshooting entries
f-trycua 44c02e3
feat(install.ps1)+docs: auto-start cua-driver serve at logon via Sche…
f-trycua 6b74ade
feat(install): -AutoStart flag + install-local.{ps1,sh} mirroring Swift
f-trycua 1c2f7b4
fix(install-local.ps1): drop broken dot-source attempt, just inline h…
f-trycua 95b9a80
docs: sanitize VM hostname/IP/user/key/paths from runbook + status re…
f-trycua File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| # Windows Session-0 Stabilization — Status Report | ||
|
|
||
| ## Good morning — TL;DR | ||
|
|
||
| While you slept I stabilized Windows cua-driver-rs end-to-end on the VM | ||
| you provisioned. **All 11 parity examples PASS** (was 6/11 before). | ||
| **Two real bugs fixed** (`doctor` segfault, `launch_app` hang), **one | ||
| focus-steal hardening** (UWP foreground-restore), **one quality filter** | ||
| (opaque system packages out of `list_apps`), **one startup banner** | ||
| (serve in Session 0 warns about GUI-tool limitations). | ||
|
|
||
| Branch `stab/windows-session0-fixes` is 7 commits ahead of | ||
| `origin/main`, all local — no PR opened per your ask. To turn into a | ||
| PR when ready: | ||
|
|
||
| ```bash | ||
| git -C <repo-root> push -u origin stab/windows-session0-fixes | ||
| gh pr create --base main --head stab/windows-session0-fixes \ | ||
| --title "fix(windows): Session-0 hardening + UWP focus-restore" \ | ||
| --body-file WINDOWS_SESSION0_STATUS.md | ||
| ``` | ||
|
|
||
| **Still wants your eyes:** the UWP focus-restore needs visual | ||
| confirmation in Session 1+ (RDP in, run the snippet under "Visual | ||
| confirmation" below). I made it stronger than my first pass (now uses | ||
| the `keybd_event` workaround to lift Windows' SetForegroundWindow | ||
| restriction) but I can't visually verify from Mac side. | ||
|
|
||
| --- | ||
|
|
||
| **Branch:** `stab/windows-session0-fixes` (local-only, no PR yet per your ask) | ||
| **Base:** `origin/main` @ 69a9dbd5 (post-#1547) | ||
| **VM:** `<vm-name>` (<vm-host>) — Rust toolchain + VS Build Tools 2022 installed | ||
| **Dev loop:** edit on Mac → `scp` changed files to `~/cua/...` on VM → `cargo build --release -p cua-driver` (~20s incremental, ~5min cold) → run. Full reference: `libs/cua-driver-rs/DEV_LOOP_WINDOWS_VM.md`. | ||
|
|
||
| ## TL;DR | ||
|
|
||
| **Two real bugs found + fixed**, both Session-0 (services / SSH-launched) edge cases: | ||
|
|
||
| 1. **`doctor` crashed with `0xC0000005 ACCESS_VIOLATION`** — COM lifecycle bug in `ui_automation_available`: `IUIAutomation` dropped AFTER `CoUninitialize`, so `IUnknown::Release` ran against a torn-down apartment. Fix: flatten probe result before tearing down COM. ✅ | ||
| 2. **`launch_app` hung indefinitely in Session 0** — two paths: `resolve_aumid_by_name` walked `shell:AppsFolder` via the interactive shell broker (doesn't exist in Session 0 → hang). `launch_uwp` itself called `IApplicationActivationManager::ActivateApplication` which also needs interactive AppX runtime (same hang). Both now short-circuit on Session 0 with `current_session_id() == Some(0)` — `resolve_aumid_by_name` returns None (falls through to ShellExecuteEx PATH lookup, which works), `launch_uwp` fails fast with a descriptive error. ✅ | ||
|
|
||
| **Plus**: foreground-restore after UWP activation (now with `keybd_event` workaround for Windows' foreground-lock restriction), three parity-example fixes (Session-0 awareness + #1545 contract), opaque-system-family UWP filter for list_apps, serve startup Session-0 banner, and `overlay_dump` example build fix. | ||
|
|
||
| ## Bugs fixed (commits on `stab/windows-session0-fixes`) | ||
|
|
||
| | Commit | Subject | | ||
| |---|---| | ||
| | `a9d9c027` | fix(windows): doctor COM lifecycle + Session 0 hardening for launch paths | | ||
| | `9e91f683` | test(windows): parity examples Session-0 aware + #1545 contract | | ||
| | `7251e73b` | feat(serve): Session-0 warning banner on Windows daemon startup | | ||
| | `2eb3c4d3` | docs(parity): update list_apps + launch_app Windows status with live evidence | | ||
| | `ac70b94d` | feat(installed_apps): filter opaque-system-family UWP packages from list_apps | | ||
| | `6f580201` | fix(installed_apps): drop Package.IsFramework() probe — hangs in Session 0 | | ||
| | `d5b5821c` | fix(launch_uwp): claim 'last input' before SetForegroundWindow restore | | ||
|
|
||
| ### Surprise bug found during this work (now fixed in `6f580201`) | ||
|
|
||
| `Package.IsFramework()` WinRT call **hangs in Session 0** (0 CPU, no progress, no error). I had added it as a "filter out framework packages from list_apps" optimization in `ac70b94d`, which silently broke list_apps for ~3 hours of debug-loop. Worth documenting: avoid WinRT property getters that may touch the AppX activation runtime when running in services context. The opaque-family-name filter still catches most framework noise. | ||
|
|
||
| ## Validated on the VM (Session 0, SSH from Mac) | ||
|
|
||
| | Tool | Status | Notes | | ||
| |---|---|---| | ||
| | `cua-driver --version` | ✅ 0.2.2 | | | ||
| | `cua-driver list-tools` | ✅ 30 tools | matches Swift surface | | ||
| | `cua-driver doctor` | ✅ exit 0 | clean run, all probes report. Session-0 warning surfaced correctly. | | ||
| | `cua-driver call get_screen_size` | ✅ 1024x768 @ 1.0 | | | ||
| | `cua-driver call get_cursor_position` | ✅ 0,0 | | | ||
| | `cua-driver call check_permissions` | ✅ elevated, post_message, uia all true | | | ||
| | `cua-driver call get_config` | ✅ returns full config | | | ||
| | `cua-driver call list_windows` | ✅ empty `[]` (expected — no desktop) | | | ||
| | `cua-driver call list_apps` | ✅ 3.7s cold, returns ~150 apps (running + installed) | | | ||
| | `cua-driver call get_accessibility_tree` | ✅ returns process list | | | ||
| | `launch_app {"name":"notepad"}` | ✅ ShellExecuteEx, pid returned | SW_SHOWNOACTIVATE (no focus steal) | | ||
| | `launch_app {"path":"C:\\..\\calc.exe"}` | ✅ ShellExecuteEx, pid returned | | | ||
| | `launch_app {"aumid":"...Calculator!App"}` | ✅ fails fast with Session-0 message (no hang) | needs interactive session to actually launch | | ||
|
|
||
| ### Parity tests | ||
| *(`cargo run --example *_parity` against running daemon)* | ||
|
|
||
| Pre-fix: 6 PASS / 5 FAIL — Session-0 expected-failures + stale post-#1545 assertions. | ||
| Post-fix: see `b8jvtpz9m.output` (in flight as of this writing). | ||
|
|
||
| ## Visual confirmation needs RDP | ||
|
|
||
| **Background-launch focus invariant for UWP apps** is now stronger than the initial best-effort: | ||
|
|
||
| - Win32 path (ShellExecuteEx + SW_SHOWNOACTIVATE): ✅ proven by code — the API contract says SW_SHOWNOACTIVATE never activates. | ||
| - UWP path (`IApplicationActivationManager::ActivateApplication(AO_NONE)`): the AppX runtime brings the app to foreground (= Start-Menu-click semantics). Now does: | ||
| 1. Snapshot prior foreground via `GetForegroundWindow` before the call | ||
| 2. Inject a VK_NONAME (0xFC) `keybd_event` press+release immediately after to claim "owner of last input" — that lifts Windows' foreground-lock restriction | ||
| 3. Call `SetForegroundWindow(prior)` in a 3 × 50ms retry loop, logging each attempt at debug | ||
|
|
||
| VK_NONAME (0xFC) doesn't map to any UI action, so no application sees a keystroke. The Session-0 short-circuit higher up bypasses this entire path so it only executes on interactive logons where focus actually matters. | ||
|
|
||
| To visually validate when you wake: | ||
|
|
||
| ```powershell | ||
| # RDP into <vm-host> as <user>, then in a PowerShell on the desktop: | ||
| $exe = "C:\Users\<user>\AppData\Local\Programs\trycua\cua-driver-rs\bin\cua-driver.exe" | ||
| # Or use the dev build: | ||
| # $exe = "$env:USERPROFILE\cua\libs\cua-driver-rs\target\release\cua-driver.exe" | ||
|
|
||
| # Open something focusable first (e.g. Notepad++ via Start menu) and start typing into it. | ||
| # Then from a *different* PowerShell window, fire: | ||
| '{"name":"calculator"}' | & $exe call launch_app | ||
| # Calculator should launch into the taskbar/background; your Notepad++ focus | ||
| # should be preserved (no visible focus steal). If focus DOES move to | ||
| # Calculator, the SetForegroundWindow restriction blocked our restore — | ||
| # we have a fallback path (push to HWND_BOTTOM) on standby. | ||
| ``` | ||
|
|
||
| ## Other improvements made | ||
|
|
||
| 1. **`eprintln!` traces in list_apps / installed_apps replaced with `tracing::debug!`** — silent at default log level. Enable with `RUST_LOG=cua_driver=debug,installed_apps=debug,list_apps=debug` when diagnosing. | ||
| 2. **Parity tests `list_apps_parity` / `list_windows_parity` / `launch_app_parity`** brought up to current contract (#1545's unified shape, Session-0 awareness, UWP fail-fast acceptance). | ||
| 3. **`overlay_dump.rs` example** — fixed `PrintWindow` + `PRINT_WINDOW_FLAGS` imports (moved to `Win32::Storage::Xps` in windows-rs 0.58). | ||
|
|
||
| ## Known issues NOT fixed (documented for next session) | ||
|
|
||
| 1. **UWP display names still show family-name fallback for some packages** — system Components and packages with unresolved `ms-resource:` tokens AND no `Properties/DisplayName` in their AppxManifest.xml fall back to their FamilyName (e.g. `1527c705-839a-4832-9118-54d4Bd6a0c89_cw5n1h2txyewy`). #1547 closed the common case; the long tail is system packages users mostly don't care about. Possible follow-ups: (a) filter out packages whose family_name matches GUID pattern AND display name is empty/equal-to-family — they're usually unactivatable system components; (b) try `Package.PublisherDisplayName` as a third fallback. | ||
|
|
||
| 2. **`SetForegroundWindow` restoration after UWP activation is best-effort** — Windows restricts foreground transfers and may silently ignore the call. Stronger options to consider: (a) `SetWindowPos(spawned_hwnd, HWND_BOTTOM, ..., SWP_NOACTIVATE)` to push the UWP window behind everything (more aggressive than macOS but guaranteed); (b) the `keybd_event` trick to give cua-driver "last input" status so SetForegroundWindow's restriction lifts (visible side effect of pressing Alt — usually OK). | ||
|
|
||
| 3. **`overlay_dump` builds — but won't run usefully in Session 0** since the overlay needs a desktop. Build-fix only. | ||
|
|
||
| 4. **Parity tests requiring foreground windows** — `list_windows`, `screenshot`, `get_window_state`, `click`, `type_text`, `hotkey`, `press_key`, `drag`, `scroll` etc. all need interactive desktop. They're tested by being called against the running daemon, but their assertions (e.g. "expected at least one visible window") are Session-0-aware where I touched them; the rest will naturally need Session 1+ to exercise meaningfully. | ||
|
|
||
| ## How to take the local fixes forward | ||
|
|
||
| ```bash | ||
| # View the local-only commits | ||
| git -C <repo-root> log --oneline origin/main..stab/windows-session0-fixes | ||
|
|
||
| # Bring them up onto a fresh branch for a PR | ||
| git -C <repo-root> checkout -b fix/windows-session0 | ||
| git -C <repo-root> merge --ff-only stab/windows-session0-fixes | ||
|
|
||
| # Then `gh pr create` as usual | ||
| ``` | ||
|
|
||
| The local branch is rebased on current `origin/main` (post-#1547). No PR opened per your instruction. | ||
|
|
||
| ## Other PRs of yours seen earlier in the session | ||
|
|
||
| - **#1546** — closed as superseded by #1547 (older diff of same domain) | ||
| - **#1547** — merged (UWP ms-resource: display name normalization) | ||
| - **#1523** — *parity(launch_app) macOS port of #1492* — has CR fixes pushed but **needs a port-onto-current-main**, not a simple rebase. Main moved significantly: `platform-macos/src/apps.rs` deleted and reorganized into `apps/mod.rs` + `apps/nsworkspace.rs`, `AppInfo` gained 3 new fields. Estimated ~30 min focused work to rebuild. Parked pending your call. | ||
|
|
||
| ## Timeline | ||
|
|
||
| - Session started ~Sun May 18 00:00 (local) | ||
| - Toolchain install on VM: 23:08 → 23:34 | ||
| - Dev loop online + first cargo build: 23:34 → 23:48 (~11min cold build) | ||
| - doctor + launch_app bugs identified + fixed: ~00:00 → ~02:00 | ||
| - This report: ~02:35 | ||
| - Resuming at next user-online checkpoint | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove host/user-specific infrastructure details from committed docs.
This report embeds concrete VM IP/host identifiers, local usernames, and workstation-specific filesystem paths. Please sanitize these to placeholders (for example,
<vm-host>,<user>,<repo-root>) before merging to avoid leaking internal environment details and to keep the doc reusable.Also applies to: 99-104, 132-139
🤖 Prompt for AI Agents