feat(cua-driver-rs)(windows): rename install paths trycua\cua-driver-rs → Cua\cua-driver (auto-migration)#1644
Conversation
…rs → Cua\cua-driver, with auto-migration
User-facing install paths drop the GitHub org prefix + Rust-port suffix:
%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin → Cua\cua-driver\bin
%USERPROFILE%\.cua-driver-rs\ → .cua-driver\
Rationale:
- The Rust port IS the canonical Windows driver — there's no Swift
Windows binary it's coexisting with anymore. The `-rs` suffix was
the disambiguator while the Swift driver still shipped Windows
binaries; it doesn't anymore, so the suffix is dead weight.
- `trycua` is the GitHub org prefix that doesn't belong in
%LOCALAPPDATA%\Programs — vendor folders there are conventionally
PascalCase company names (Microsoft\, Google\, NVIDIA\, ...).
`Cua\` matches that convention.
## Auto-migration
install.ps1 detects the v0.2.13-and-earlier layout (when default paths
are in use, i.e. no $env:CUA_DRIVER_RS_INSTALL_DIR or
$env:CUA_DRIVER_RS_HOME override) and migrates transparently before
laying down the new install:
1. Stop any cua-driver / cua-driver-uia daemon pinning legacy binary
files open.
2. Unregister the cua-driver-serve Scheduled Task (idempotent; uses
the same defensive $ErrorActionPreference handling as
uninstall.ps1's #1633 fix).
3. Remove the legacy visible bin junction + empty parent dirs
(cua-driver-rs\ and trycua\ when the latter is empty after the
pass — vendor dir is preserved if other apps live under it).
4. Remove the legacy package home tree (.cua-driver-rs\).
5. Prune the legacy bin path from User PATH (the new install adds
the new path; without pruning we'd accumulate stale PATH entries
on every upgrade).
uninstall.ps1 always sweeps legacy paths too, so a single
`irm uninstall.ps1 | iex` leaves nothing behind even when run AFTER
the user has already upgraded to the new layout.
## Env var names unchanged
$env:CUA_DRIVER_RS_INSTALL_DIR and $env:CUA_DRIVER_RS_HOME keep the
`_RS_` infix even though the underlying paths are renamed. Changing
env var names silently would break existing automation (CI, devx
scripts, dotfiles) that pins a custom install dir.
## Compat
- v0.2.13 → v0.2.14 upgrade via `irm install.ps1 | iex`: transparent
one-shot migration.
- Fresh v0.2.14 install: new paths only, no legacy detection needed.
- User with $env:CUA_DRIVER_RS_INSTALL_DIR or _HOME set: their
override wins; legacy migration skipped to avoid surprising them.
- Crate names (cua-driver, cua-driver-rs), release tag prefix
(cua-driver-rs-v0.2.x), CD asset filenames, binary names
(cua-driver.exe), Scheduled Task name (cua-driver-serve), and named
pipe (\\.\pipe\cua-driver) are all unchanged — only the user-facing
install paths move.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR migrates the Windows cua-driver installation layout from the legacy ChangesWindows Install/Uninstall Layout Migration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/content/docs/cua-driver/guide/getting-started/installation.mdx (2)
230-230:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winLockfile example path references legacy location.
The PowerShell example shows the old
.cua-driver-rspath for the lockfile, but the new home directory is.cua-driver.Proposed fix
-Get-Content $env:USERPROFILE\.cua-driver-rs\install.lock +Get-Content $env:USERPROFILE\.cua-driver\install.lock🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/content/docs/cua-driver/guide/getting-started/installation.mdx` at line 230, Update the PowerShell example that references the legacy lockfile path by replacing the ".cua-driver-rs" folder with the new ".cua-driver" folder; specifically modify the line containing the command string "Get-Content $env:USERPROFILE\.cua-driver-rs\install.lock" so it points to "$env:USERPROFILE\.cua-driver\install.lock" (ensure only the folder name changes and keep the rest of the example intact).
176-178:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winEnv-var defaults table still references legacy paths.
The table shows old defaults (
trycua\cua-driver-rs\binand.cua-driver-rs) while the rest of the document has been updated to the new paths (Cua\cua-driver\binand.cua-driver). This will confuse users.Proposed fix
-| `CUA_DRIVER_RS_INSTALL_DIR` | `~/.local/bin` | `%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin` | The visible PATH-entry directory. On Windows this is itself a junction. | -| `CUA_DRIVER_RS_HOME` | `~/.cua-driver-rs` | `%USERPROFILE%\.cua-driver-rs` | Package home — holds `packages/releases/<v>/` and `packages/current`. | +| `CUA_DRIVER_RS_INSTALL_DIR` | `~/.local/bin` | `%LOCALAPPDATA%\Programs\Cua\cua-driver\bin` | The visible PATH-entry directory. On Windows this is itself a junction. | +| `CUA_DRIVER_RS_HOME` | `~/.cua-driver-rs` | `%USERPROFILE%\.cua-driver` | Package home — holds `packages/releases/<v>/` and `packages/current`. |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/content/docs/cua-driver/guide/getting-started/installation.mdx` around lines 176 - 178, Update the env-var defaults table to match the new path conventions: replace legacy Windows path `%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin` with `%LOCALAPPDATA%\Programs\Cua\cua-driver\bin` and replace the package home `~/.cua-driver-rs` / `%USERPROFILE%\.cua-driver-rs` with `~/.cua-driver` / `%USERPROFILE%\.cua-driver` for the CUA_DRIVER_RS_INSTALL_DIR and CUA_DRIVER_RS_HOME rows respectively; keep the CUA_DRIVER_RS_NO_MODIFY_PATH row text unchanged except where it echoes the same path string so those references also use the new `Cua\cua-driver\bin` and `.cua-driver` values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@libs/cua-driver/scripts/install.ps1`:
- Around line 919-931: Remove-LegacyInstall currently deletes
$LegacyVisibleBinDir even when it is a real directory; mirror the safety in
Ensure-Junction by checking the item's reparse status first (use Get-Item to set
$item and compute $isReparse as in the diff), and only delete when $isReparse is
true (junction) — otherwise skip removal, write a warning/notice (e.g., via
Write-Host) that a non-junction directory was left intact, and avoid Remove-Item
on non-reparse directories to prevent accidental user data deletion; update the
logic inside Remove-LegacyInstall around $LegacyVisibleBinDir to perform this
check and early-return or continue accordingly.
In `@libs/cua-driver/scripts/uninstall.ps1`:
- Around line 280-288: The cleanup for $LegacyVisibleBinDir currently removes
the path regardless of type; change the block around Test-IsReparsePoint and
Remove-Item so it mirrors the logic used for $VisibleBinDir: call
Test-IsReparsePoint $LegacyVisibleBinDir and only Remove-Item when it returns
true (treat as a junction), otherwise skip removal and call Write-Step (or a
warning) indicating the path was not a reparse point and was left intact; keep
the existing messages (use "removed legacy junction $LegacyVisibleBinDir" on
success and a clear "skipped non-junction legacy path $LegacyVisibleBinDir"
message when not a reparse point), leaving Test-IsReparsePoint, Remove-Item, and
Write-Step as the referenced symbols.
---
Outside diff comments:
In `@docs/content/docs/cua-driver/guide/getting-started/installation.mdx`:
- Line 230: Update the PowerShell example that references the legacy lockfile
path by replacing the ".cua-driver-rs" folder with the new ".cua-driver" folder;
specifically modify the line containing the command string "Get-Content
$env:USERPROFILE\.cua-driver-rs\install.lock" so it points to
"$env:USERPROFILE\.cua-driver\install.lock" (ensure only the folder name changes
and keep the rest of the example intact).
- Around line 176-178: Update the env-var defaults table to match the new path
conventions: replace legacy Windows path
`%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin` with
`%LOCALAPPDATA%\Programs\Cua\cua-driver\bin` and replace the package home
`~/.cua-driver-rs` / `%USERPROFILE%\.cua-driver-rs` with `~/.cua-driver` /
`%USERPROFILE%\.cua-driver` for the CUA_DRIVER_RS_INSTALL_DIR and
CUA_DRIVER_RS_HOME rows respectively; keep the CUA_DRIVER_RS_NO_MODIFY_PATH row
text unchanged except where it echoes the same path string so those references
also use the new `Cua\cua-driver\bin` and `.cua-driver` values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 316918ac-1b23-4e3f-951b-97352793aba0
📒 Files selected for processing (3)
docs/content/docs/cua-driver/guide/getting-started/installation.mdxlibs/cua-driver/scripts/install.ps1libs/cua-driver/scripts/uninstall.ps1
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | ||
| try { | ||
| $item = Get-Item -LiteralPath $LegacyVisibleBinDir -Force -ErrorAction Stop | ||
| $isReparse = ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0 | ||
| if ($isReparse) { | ||
| # NTFS junction — delete the link, not the target. | ||
| [System.IO.Directory]::Delete($LegacyVisibleBinDir, $false) | ||
| } else { | ||
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Recurse -Force -ErrorAction SilentlyContinue | ||
| } | ||
| } catch { | ||
| Write-Host " (could not remove $LegacyVisibleBinDir : $($_.Exception.Message))" -ForegroundColor Yellow | ||
| } |
There was a problem hiding this comment.
Legacy cleanup removes non-junction directories, unlike main install logic.
The Ensure-Junction function (lines 500-505) explicitly refuses to replace an existing non-junction directory at the bin path. However, Remove-LegacyInstall will remove $LegacyVisibleBinDir even if it's a real directory (line 927). This inconsistency could delete user data if someone manually created a directory at the legacy path.
Consider aligning with the safety check in Ensure-Junction:
Proposed fix - skip non-junction directories
if (Test-Path -LiteralPath $LegacyVisibleBinDir) {
try {
$item = Get-Item -LiteralPath $LegacyVisibleBinDir -Force -ErrorAction Stop
$isReparse = ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0
if ($isReparse) {
# NTFS junction — delete the link, not the target.
[System.IO.Directory]::Delete($LegacyVisibleBinDir, $false)
} else {
- Remove-Item -LiteralPath $LegacyVisibleBinDir -Recurse -Force -ErrorAction SilentlyContinue
+ Write-Host " (legacy $LegacyVisibleBinDir is not a junction — skipping to preserve user data)" -ForegroundColor Yellow
}
} catch {
Write-Host " (could not remove $LegacyVisibleBinDir : $($_.Exception.Message))" -ForegroundColor Yellow
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | |
| try { | |
| $item = Get-Item -LiteralPath $LegacyVisibleBinDir -Force -ErrorAction Stop | |
| $isReparse = ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0 | |
| if ($isReparse) { | |
| # NTFS junction — delete the link, not the target. | |
| [System.IO.Directory]::Delete($LegacyVisibleBinDir, $false) | |
| } else { | |
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Recurse -Force -ErrorAction SilentlyContinue | |
| } | |
| } catch { | |
| Write-Host " (could not remove $LegacyVisibleBinDir : $($_.Exception.Message))" -ForegroundColor Yellow | |
| } | |
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | |
| try { | |
| $item = Get-Item -LiteralPath $LegacyVisibleBinDir -Force -ErrorAction Stop | |
| $isReparse = ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0 | |
| if ($isReparse) { | |
| # NTFS junction — delete the link, not the target. | |
| [System.IO.Directory]::Delete($LegacyVisibleBinDir, $false) | |
| } else { | |
| Write-Host " (legacy $LegacyVisibleBinDir is not a junction — skipping to preserve user data)" -ForegroundColor Yellow | |
| } | |
| } catch { | |
| Write-Host " (could not remove $LegacyVisibleBinDir : $($_.Exception.Message))" -ForegroundColor Yellow | |
| } | |
| } |
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'install.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@libs/cua-driver/scripts/install.ps1` around lines 919 - 931,
Remove-LegacyInstall currently deletes $LegacyVisibleBinDir even when it is a
real directory; mirror the safety in Ensure-Junction by checking the item's
reparse status first (use Get-Item to set $item and compute $isReparse as in the
diff), and only delete when $isReparse is true (junction) — otherwise skip
removal, write a warning/notice (e.g., via Write-Host) that a non-junction
directory was left intact, and avoid Remove-Item on non-reparse directories to
prevent accidental user data deletion; update the logic inside
Remove-LegacyInstall around $LegacyVisibleBinDir to perform this check and
early-return or continue accordingly.
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | ||
| if (Test-IsReparsePoint $LegacyVisibleBinDir) { | ||
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue | ||
| Write-Step "removed legacy junction $LegacyVisibleBinDir" | ||
| } else { | ||
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue | ||
| Write-Step "removed legacy directory $LegacyVisibleBinDir" | ||
| } | ||
| } |
There was a problem hiding this comment.
Legacy cleanup removes non-junction directories without the safety check applied to main paths.
Step 3 (lines 233-236) refuses to remove $VisibleBinDir if it's not a reparse point, but step 6 removes $LegacyVisibleBinDir regardless of whether it's a junction. For consistency and safety, consider applying the same protection:
Proposed fix - align with step 3's safety check
if (Test-Path -LiteralPath $LegacyVisibleBinDir) {
if (Test-IsReparsePoint $LegacyVisibleBinDir) {
Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue
Write-Step "removed legacy junction $LegacyVisibleBinDir"
} else {
- Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue
- Write-Step "removed legacy directory $LegacyVisibleBinDir"
+ Write-WarningStep "$LegacyVisibleBinDir exists but is not a reparse point — skipping."
+ Write-WarningStep " install.ps1 only creates junctions at this path, so this may be a hand-managed directory."
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | |
| if (Test-IsReparsePoint $LegacyVisibleBinDir) { | |
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue | |
| Write-Step "removed legacy junction $LegacyVisibleBinDir" | |
| } else { | |
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue | |
| Write-Step "removed legacy directory $LegacyVisibleBinDir" | |
| } | |
| } | |
| if (Test-Path -LiteralPath $LegacyVisibleBinDir) { | |
| if (Test-IsReparsePoint $LegacyVisibleBinDir) { | |
| Remove-Item -LiteralPath $LegacyVisibleBinDir -Force -Recurse -ErrorAction SilentlyContinue | |
| Write-Step "removed legacy junction $LegacyVisibleBinDir" | |
| } else { | |
| Write-WarningStep "$LegacyVisibleBinDir exists but is not a reparse point — skipping." | |
| Write-WarningStep " install.ps1 only creates junctions at this path, so this may be a hand-managed directory." | |
| } | |
| } |
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'uninstall.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@libs/cua-driver/scripts/uninstall.ps1` around lines 280 - 288, The cleanup
for $LegacyVisibleBinDir currently removes the path regardless of type; change
the block around Test-IsReparsePoint and Remove-Item so it mirrors the logic
used for $VisibleBinDir: call Test-IsReparsePoint $LegacyVisibleBinDir and only
Remove-Item when it returns true (treat as a junction), otherwise skip removal
and call Write-Step (or a warning) indicating the path was not a reparse point
and was left intact; keep the existing messages (use "removed legacy junction
$LegacyVisibleBinDir" on success and a clear "skipped non-junction legacy path
$LegacyVisibleBinDir" message when not a reparse point), leaving
Test-IsReparsePoint, Remove-Item, and Write-Step as the referenced symbols.
…driver (PR #1644 completion) (#1650) PR #1644's path rename (Programs\trycua\cua-driver-rs → Programs\Cua\cua-driver and ~/.cua-driver-rs → ~/.cua-driver) only updated the install scripts. The Rust binary's telemetry module hardcodes ~/.cua-driver-rs/ for its .telemetry_id + .installation_recorded files, so every daemon run recreated the legacy directory in the user's home regardless of the new install path. Discovered during cuademo SSH dogfood of v0.2.15: cleanup script removed the legacy `.cua-driver-rs/` four times; every spin of `cua-driver serve` brought it back with `.telemetry_id` + `.installation_recorded` files timestamped at runtime. ## Changes - `crates/cua-driver/src/telemetry.rs::HOME_SUBDIRECTORY`: `.cua-driver-rs` → `.cua-driver`. Doc comment updated to note the rename + describe the one-shot migration of legacy telemetry files. - New `migrate_legacy_telemetry_home()` runs once per process at the start of `load_or_create_install_id_uncached`. Best-effort move of `.telemetry_id` + `.installation_recorded` from `.cua-driver-rs/` to `.cua-driver/` (preserving the per-install UUID so analytics survive the rename), then `remove_dir` on the legacy directory if empty. - `crates/cua-driver/src/doctor.rs::probe_home_dir` + `probe_telemetry`: same `.cua-driver-rs` → `.cua-driver` rename so `cua-driver doctor` reports the canonical path. ## Verification cuademo SSH session, v0.2.15 installed at new paths but with telemetry still writing legacy: Before this fix: Remove-Item .cua-driver-rs; spin daemon; check → .cua-driver-rs/.telemetry_id recreated every time After this fix (v0.2.16): Remove-Item .cua-driver-rs; spin daemon; check → .cua-driver/.telemetry_id created; .cua-driver-rs not recreated Existing users with a v0.2.15-or-earlier `.cua-driver-rs/` get a transparent migration on first v0.2.16 launch: the telemetry UUID and install-recorded marker move to `.cua-driver/`, then `.cua-driver-rs/` removes itself. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
User-facing install paths drop the GitHub org prefix + Rust-port suffix:
Rationale
Auto-migration
`install.ps1` detects the v0.2.13-and-earlier layout (when default paths are in use, i.e. no `CUA_DRIVER_RS_INSTALL_DIR` / `CUA_DRIVER_RS_HOME` override) and migrates transparently before installing the new layout. Steps mirror uninstall.ps1's cleanup: stop daemon → unregister task → remove legacy junctions + empty parent dirs → remove legacy package home → prune legacy PATH entry.
`uninstall.ps1` always sweeps both layouts so a single `irm uninstall.ps1 | iex` leaves nothing behind.
What's preserved
Compat table
Test plan
Out of scope (follow-ups)
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation