Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ The legacy `libs/cua-driver-rs/scripts/install.{sh,ps1}` URLs continue to work v
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x86_64' }
$url = "https://github.com/trycua/cua/releases/download/cua-driver-rs-v$version/cua-driver-rs-$version-windows-$arch-binary.zip"
iwr $url -OutFile $env:TEMP\cua.zip -UseBasicParsing
$dest = "$env:LOCALAPPDATA\Programs\trycua\cua-driver-rs\bin"
$dest = "$env:LOCALAPPDATA\Programs\Cua\cua-driver\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Expand-Archive -Force -Path $env:TEMP\cua.zip -DestinationPath $dest
# Idempotent User PATH update — only add $dest if not already present.
Expand All @@ -96,7 +96,7 @@ The Windows installer auto-detects host architecture (x64 / arm64) via `[System.

It runs **without admin** and **without Developer Mode**.

It also appends `%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin` to your **User-scope `Path`** so `cua-driver --version` resolves in any new PowerShell window. The write is idempotent (re-running the installer never duplicates the entry) and falls back to printing manual `[Environment]::SetEnvironmentVariable(...)` instructions if the registry write is blocked (group policy, locked-down account). Pass `-NoPathUpdate` to suppress the auto-add — useful when you manage `Path` out-of-band via chezmoi / dotfiles / GPO:
It also appends `%LOCALAPPDATA%\Programs\Cua\cua-driver\bin` to your **User-scope `Path`** so `cua-driver --version` resolves in any new PowerShell window. (v0.2.13 and earlier used `Programs\trycua\cua-driver-rs\bin`; the v0.2.14 installer auto-migrates the legacy layout.) The write is idempotent (re-running the installer never duplicates the entry) and falls back to printing manual `[Environment]::SetEnvironmentVariable(...)` instructions if the registry write is blocked (group policy, locked-down account). Pass `-NoPathUpdate` to suppress the auto-add — useful when you manage `Path` out-of-band via chezmoi / dotfiles / GPO:

```powershell
# Fetch + invoke explicitly so we can pass the switch:
Expand Down Expand Up @@ -126,16 +126,18 @@ $CUA_DRIVER_RS_INSTALL_DIR/cua-driver -> $CUA_DRIVER_RS_HOME/packages/current/cu
**Windows**

```
%USERPROFILE%\.cua-driver-rs\ ($env:CUA_DRIVER_RS_HOME)
%USERPROFILE%\.cua-driver\ ($env:CUA_DRIVER_RS_HOME)
packages\
releases\
0.2.0-x86_64-pc-windows-msvc\cua-driver.exe (real binary, immutable)
0.2.1-x86_64-pc-windows-msvc\cua-driver.exe (real binary, immutable)
current\ (directory junction → releases\0.2.1-...)
%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin\ ($env:CUA_DRIVER_RS_INSTALL_DIR)
0.2.14-x86_64-pc-windows-msvc\cua-driver.exe (real binary, immutable)
0.2.15-x86_64-pc-windows-msvc\cua-driver.exe (real binary, immutable)
current\ (directory junction → releases\0.2.15-...)
%LOCALAPPDATA%\Programs\Cua\cua-driver\bin\ ($env:CUA_DRIVER_RS_INSTALL_DIR)
(directory junction → packages\current)
```

v0.2.13 and earlier used `%LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin\` and `%USERPROFILE%\.cua-driver-rs\`. The v0.2.14+ installer detects the legacy layout and migrates transparently — stop any running daemon, delete the legacy task / junctions / package home, prune the legacy PATH entry, then install at the new path.

Both junctions are NTFS reparse points (`IO_REPARSE_TAG_MOUNT_POINT`), so the whole PATH-resolution chain `bin\ → current\ → releases\<v>\cua-driver.exe` is two filesystem hops transparently served from whichever release the inner junction currently points at.

#### Atomic upgrades and rollback
Expand Down
132 changes: 125 additions & 7 deletions libs/cua-driver/scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@
# Layout on disk (three tiers, two directory junctions):
#
# <visibleBinDir> [directory junction → currentDir]
# = %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin
# = %LOCALAPPDATA%\Programs\Cua\cua-driver\bin
# <currentDir> [directory junction → release dir]
# = %USERPROFILE%\.cua-driver-rs\packages\current
# = %USERPROFILE%\.cua-driver\packages\current
# <release dir> [real directory, immutable per version]
# = %USERPROFILE%\.cua-driver-rs\packages\releases\<version>-<target>
# = %USERPROFILE%\.cua-driver\packages\releases\<version>-<target>
# cua-driver.exe
#
# Path layout renamed v0.2.14: `Programs\trycua\cua-driver-rs\` →
# `Programs\Cua\cua-driver\` and `.cua-driver-rs\` → `.cua-driver\`. The
# Rust port IS the canonical Windows driver now (no `-rs` suffix needed),
# and `trycua` is the GitHub org prefix that doesn't belong in
# %LOCALAPPDATA%\Programs. Legacy installs are auto-migrated at the next
# `irm install.ps1 | iex` run.
#
# PATH consumers see <visibleBinDir>; the contents are transparently
# served from whichever release the inner junction currently points at.
# Atomic upgrade = retarget <currentDir> at a newer release dir.
Expand All @@ -34,9 +41,9 @@
# Env overrides:
# $env:CUA_DRIVER_RS_VERSION pin a specific release (e.g. "0.2.0")
# $env:CUA_DRIVER_RS_INSTALL_DIR override the visible PATH-entry dir
# (default %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin)
# (default %LOCALAPPDATA%\Programs\Cua\cua-driver\bin)
# $env:CUA_DRIVER_RS_HOME override the package home
# (default %USERPROFILE%\.cua-driver-rs)
# (default %USERPROFILE%\.cua-driver)
# $env:CUA_DRIVER_RS_KEEP_VERSIONS keep the N most recent per-version
# release dirs after install; older ones
# are deleted (default 5; set 0 to
Expand Down Expand Up @@ -107,15 +114,33 @@ $Script:CuaDriverRsBakedVersion = "0.2.13"
if ($env:CUA_DRIVER_RS_INSTALL_DIR) {
$VisibleBinDir = $env:CUA_DRIVER_RS_INSTALL_DIR
} else {
$VisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\trycua\cua-driver-rs\bin"
# Path layout renamed v0.2.14: `Programs\trycua\cua-driver-rs\` →
# `Programs\Cua\cua-driver\`. The Rust port IS the canonical Windows
# driver now (no more `-rs` suffix needed in user-facing paths), and
# `trycua` is the GitHub org prefix that doesn't belong in
# %LOCALAPPDATA% — vendor folders there are conventionally PascalCase
# company names. The env var name keeps the `_RS_` infix so existing
# automation pinning a custom install dir doesn't break silently.
$VisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\Cua\cua-driver\bin"
}

# Legacy install paths from v0.2.13 and earlier. The uninstall path checks
# both; the install path nukes any legacy install before laying down the
# new one, so v0.2.13 → v0.2.14+ is a transparent upgrade.
$LegacyVisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\trycua\cua-driver-rs\bin"
$LegacyVendorDir = Join-Path $env:LOCALAPPDATA "Programs\trycua"

if ($env:CUA_DRIVER_RS_HOME) {
$HomeDir = $env:CUA_DRIVER_RS_HOME
} else {
$HomeDir = Join-Path $env:USERPROFILE ".cua-driver-rs"
# Same rename: `.cua-driver-rs/` → `.cua-driver/`. The `-rs` suffix
# was the Rust-port-vs-Swift-driver disambiguator while the Swift one
# still existed for Windows; it doesn't anymore.
$HomeDir = Join-Path $env:USERPROFILE ".cua-driver"
}

$LegacyHomeDir = Join-Path $env:USERPROFILE ".cua-driver-rs"

$PackagesDir = Join-Path $HomeDir "packages"
$ReleasesDir = Join-Path $PackagesDir "releases"
$CurrentDir = Join-Path $PackagesDir "current"
Expand Down Expand Up @@ -850,6 +875,99 @@ Write-Step "cua-driver-rs installer (Windows)"
Write-Step " install dir : $VisibleBinDir"
Write-Step " package home: $HomeDir"

function Remove-LegacyInstall {
# Best-effort cleanup of v0.2.13-and-earlier install paths. Runs before
# any new install when default paths are in use (so users who override
# CUA_DRIVER_RS_INSTALL_DIR / CUA_DRIVER_RS_HOME aren't surprised by us
# touching legacy locations). Mirrors uninstall.ps1's logic so the
# transition is symmetric: a single `irm install.ps1 | iex` upgrades
# from v0.2.13 → v0.2.14+ without orphan files at the old layout.
if ($env:CUA_DRIVER_RS_INSTALL_DIR -or $env:CUA_DRIVER_RS_HOME) {
return
}
$hasLegacy = (Test-Path -LiteralPath $LegacyVisibleBinDir) -or `
(Test-Path -LiteralPath $LegacyHomeDir)
if (-not $hasLegacy) { return }

Write-Step "detected legacy install layout (v0.2.13 or earlier); migrating to Cua\cua-driver"

# 1. Stop any cua-driver / cua-driver-uia daemon that's pinning the
# legacy binary directory open. Use the regular Get-Process route —
# these are user-owned processes, kill is allowed.
$procs = Get-Process -Name "cua-driver","cua-driver-uia" -ErrorAction SilentlyContinue
if ($procs) {
foreach ($p in $procs) {
try { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue } catch {}
}
Start-Sleep -Milliseconds 250
}

# 2. Unregister the autostart Scheduled Task if present. Idempotent —
# schtasks /Query returns non-zero when the task is absent, which we
# swallow (matches uninstall.ps1's pattern for the same call).
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
try {
& schtasks.exe /Delete /TN "cua-driver-serve" /F 2>$null | Out-Null
} finally {
$ErrorActionPreference = $prevEAP
}

# 3. Remove the visible bin junction (only when it's actually a reparse
# point — refuse to clobber a real directory). Then walk up and
# remove the empty `trycua` vendor dir if nothing else lives there.
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
}
Comment on lines +919 to +931

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Suggested change
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.

}
# Remove the parent `cua-driver-rs` dir (now empty) and the vendor
# `trycua` dir if no other apps live under it.
$legacyParent = Split-Path -Parent $LegacyVisibleBinDir
if ((Test-Path -LiteralPath $legacyParent) -and -not (Get-ChildItem -LiteralPath $legacyParent -Force -ErrorAction SilentlyContinue)) {
Remove-Item -LiteralPath $legacyParent -Force -ErrorAction SilentlyContinue
}
if ((Test-Path -LiteralPath $LegacyVendorDir) -and -not (Get-ChildItem -LiteralPath $LegacyVendorDir -Force -ErrorAction SilentlyContinue)) {
Remove-Item -LiteralPath $LegacyVendorDir -Force -ErrorAction SilentlyContinue
}

# 4. Remove the legacy package home tree.
if (Test-Path -LiteralPath $LegacyHomeDir) {
try {
Remove-Item -LiteralPath $LegacyHomeDir -Recurse -Force -ErrorAction Stop
} catch {
Write-Host " (could not remove $LegacyHomeDir : $($_.Exception.Message))" -ForegroundColor Yellow
}
}

# 5. Prune the legacy bin dir from User PATH. The new install will add
# the new path right after this; without removing the old we'd
# accumulate stale PATH entries on every upgrade.
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($userPath) {
$legacyNorm = $LegacyVisibleBinDir.TrimEnd('\').ToLowerInvariant()
$cleaned = ($userPath -split ';' |
Where-Object { $_ -and $_.TrimEnd('\').ToLowerInvariant() -ne $legacyNorm }) -join ';'
if ($cleaned -ne $userPath) {
[Environment]::SetEnvironmentVariable('Path', $cleaned, 'User')
Write-Step " pruned legacy $LegacyVisibleBinDir from User PATH"
}
}

Write-Step "legacy install removed"
}

Remove-LegacyInstall

# Serialize concurrent installs per $HomeDir. The lock is released in
# the finally below — covers normal exit, errors, and Ctrl-C (which
# triggers PowerShell's pipeline-stop = finally still runs).
Expand Down
68 changes: 59 additions & 9 deletions libs/cua-driver/scripts/uninstall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
# `cua-driver autostart enable` or install.ps1 -AutoStart)
# - Any running cua-driver.exe processes (so file handles don't pin
# the binary directory open during the delete pass)
# - <visibleBinDir> = %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin (directory junction)
# - <currentDir> = %USERPROFILE%\.cua-driver-rs\packages\current (directory junction)
# - <packageHome> = %USERPROFILE%\.cua-driver-rs\ (entire tree:
# - <visibleBinDir> = %LOCALAPPDATA%\Programs\Cua\cua-driver\bin (directory junction)
# - <currentDir> = %USERPROFILE%\.cua-driver\packages\current (directory junction)
# - <packageHome> = %USERPROFILE%\.cua-driver\ (entire tree:
# releases, lockfile,
# telemetry id,
# install marker,
Expand All @@ -38,9 +38,13 @@
#
# Env overrides (mirror install.ps1's variable names):
# $env:CUA_DRIVER_RS_INSTALL_DIR visible bin dir to remove
# (default %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin)
# (default %LOCALAPPDATA%\Programs\Cua\cua-driver\bin;
# v0.2.13 and earlier used Programs\trycua\cua-driver-rs\bin
# — that legacy path is always cleaned up too)
# $env:CUA_DRIVER_RS_HOME package home to remove
# (default %USERPROFILE%\.cua-driver-rs)
# (default %USERPROFILE%\.cua-driver;
# v0.2.13 and earlier used .cua-driver-rs —
# that legacy path is always cleaned up too)
#
# Params:
# -Force non-interactive: skip the "remove? [y/N]" prompt before
Expand All @@ -62,15 +66,25 @@ $ProgressPreference = "SilentlyContinue"
if ($env:CUA_DRIVER_RS_INSTALL_DIR) {
$VisibleBinDir = $env:CUA_DRIVER_RS_INSTALL_DIR
} else {
$VisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\trycua\cua-driver-rs\bin"
# New layout (v0.2.14+). Path rename rationale: see install.ps1.
$VisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\Cua\cua-driver\bin"
}

# Legacy bin dir from v0.2.13 and earlier. We also clean these up so a
# fresh uninstall after upgrading leaves nothing behind. Empty-vendor-dir
# (Programs\trycua\) gets pruned if no other apps live under it.
$LegacyVisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\trycua\cua-driver-rs\bin"
$LegacyVendorDir = Join-Path $env:LOCALAPPDATA "Programs\trycua"

if ($env:CUA_DRIVER_RS_HOME) {
$HomeDir = $env:CUA_DRIVER_RS_HOME
} else {
$HomeDir = Join-Path $env:USERPROFILE ".cua-driver-rs"
$HomeDir = Join-Path $env:USERPROFILE ".cua-driver"
}

# Legacy package home from v0.2.13 and earlier.
$LegacyHomeDir = Join-Path $env:USERPROFILE ".cua-driver-rs"

$PackagesDir = Join-Path $HomeDir "packages"
$CurrentDir = Join-Path $PackagesDir "current"
$AutoStartTask = "cua-driver-serve"
Expand Down Expand Up @@ -258,7 +272,42 @@ if (Test-Path -LiteralPath $HomeDir) {
Write-Step "no package home at $HomeDir (skipping)"
}

# 6. Skill junctions. Only remove reparse points — leave a real dir
# 6. Legacy install layout from v0.2.13 and earlier
# (`Programs\trycua\cua-driver-rs\` + `.cua-driver-rs\`). We always
# sweep these so a fresh uninstall after upgrading via install.ps1
# leaves nothing behind. Skip silently when the legacy paths don't
# exist — common case post-v0.2.14.
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"
}
}
Comment on lines +280 to +288

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Suggested change
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.

# Empty cua-driver-rs parent (under trycua\)
$legacyParent = Split-Path -Parent $LegacyVisibleBinDir
if ((Test-Path -LiteralPath $legacyParent) -and -not (Get-ChildItem -LiteralPath $legacyParent -Force -ErrorAction SilentlyContinue)) {
Remove-Item -LiteralPath $legacyParent -Force -ErrorAction SilentlyContinue
Write-Step "removed empty legacy parent $legacyParent"
}
# Empty trycua vendor dir
if ((Test-Path -LiteralPath $LegacyVendorDir) -and -not (Get-ChildItem -LiteralPath $LegacyVendorDir -Force -ErrorAction SilentlyContinue)) {
Remove-Item -LiteralPath $LegacyVendorDir -Force -ErrorAction SilentlyContinue
Write-Step "removed empty legacy vendor dir $LegacyVendorDir"
}
# Legacy package home
if (Test-Path -LiteralPath $LegacyHomeDir) {
Remove-Item -LiteralPath $LegacyHomeDir -Force -Recurse -ErrorAction SilentlyContinue
if (Test-Path -LiteralPath $LegacyHomeDir) {
Write-WarningStep "$LegacyHomeDir was not fully removed — some files may still be locked."
} else {
Write-Step "removed legacy package home $LegacyHomeDir"
}
}

# 7. Skill junctions. Only remove reparse points — leave a real dir
# in place (a user with a hand-managed cua-driver-rs skill dir
# gets to keep it). Same defensive shape as Linux/macOS.
foreach ($skillLink in $SkillJunctions) {
Expand Down Expand Up @@ -286,7 +335,8 @@ Write-Host ""
Write-Host " claude mcp remove cua-driver-rs"
Write-Host ""
Write-Host " Or edit ~/.claude.json directly and delete entries whose 'command' points at"
Write-Host " cua-driver.exe under %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin\."
Write-Host " cua-driver.exe under %LOCALAPPDATA%\Programs\Cua\cua-driver\bin\"
Write-Host " (or the legacy %LOCALAPPDATA%\Programs\trycua\cua-driver-rs\bin\ from v0.2.13 and earlier)."
Write-Host ""
Write-Host "PATH:"
Write-Host " If you added $VisibleBinDir to your User PATH after the install, remove it:"
Expand Down
Loading