mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-14 19:24:54 +00:00
* feat(cua-driver): vendor trycua/cua driver with 1000-normalized coordinate support
Vendor libs/cua-driver from trycua/cua into packages/cua-driver as the
basis for qwen-code's computer-use backend, adding an opt-in relative
(1000x1000 normalized) coordinate mode for Qwen-VL clients.
- coord_norm.rs: 0-1000 <-> pixel conversion, per-(pid,window_id) size
cache, tools/list description rewrite (TDD, 27 tests)
- ToolRegistry: normalized field + invoke input/output hooks
- protocol.rs: system-instruction coordinate wording switched by mode
- serve.rs: daemon list path description rewrite (input_schema aware)
- main.rs: CUA_DRIVER_RS_COORDINATE_SPACE env seed
Default coordinate_space=pixels => zero behavior change for existing
pixel clients. Set CUA_DRIVER_RS_COORDINATE_SPACE=normalized_1000 to
enable. Excludes rust/target build output.
* feat(cua-driver): make normalized coordinate scale configurable
Add CUA_DRIVER_RS_COORDINATE_SCALE (default 1000) so the normalization
full-scale can absorb the Qwen 999-vs-1000 cookbook ambiguity without a
recompile. norm_to_px/px_to_norm now take an explicit scale; denormalize_args
reads the process-wide COORDINATE_SCALE seeded once at startup from env.
* ci(cua-driver): add cross-platform release workflow for vendored driver
Standalone GitHub Action that builds, signs, and releases the vendored
cua-driver under packages/cua-driver. Adapted from upstream trycua/cua
cd-rust-cua-driver.yml:
- macOS: universal binary (lipo arm64+x86_64), codesigned + notarized into
CuaDriver.app using qwen-code's existing secrets (MAC_CSC_LINK cert +
App Store Connect API key notarization); Developer ID identity is
auto-discovered from the imported cert.
- Linux: x86_64 + arm64, built in debian:11 for a glibc 2.31 floor.
- Windows: x86_64 + arm64, unsigned (no EV cert, matches upstream).
- Release: softprops/action-gh-release on cua-driver-rs-v* tags or manual
dispatch, prerelease.
Triggered by tag push (cua-driver-rs-v*) or workflow_dispatch.
* chore(cua-driver): rebrand vendored driver as qwen-cua-driver
Rename the vendored trycua/cua driver so the fork installs and runs
independently of any upstream trycua install:
- binary cua-driver -> qwen-cua-driver
- bundle CuaDriver.app -> QwenCuaDriver.app
- bundle id com.trycua.driver -> com.qwencode.cua-driver
Updates the cargo/uia manifests, Info.plist, bundle/proxy launch paths,
permission/health-report wording, the install/build scripts, and the
cross-platform release workflow.
* feat(cua-driver): finish relative-coordinate mode — toggle, scale, zoom/move_cursor
- CUA_DRIVER_RS_COORDINATE_SPACE is now a 1/0 toggle (via is_env_truthy);
default off keeps pixel mode byte-identical to upstream.
- Thread CUA_DRIVER_RS_COORDINATE_SCALE through every coordinate surface
(was hardcoded 1000): input denormalization already used it; now the
rewritten screenshot dims, the tool/param descriptions, and the agent
instructions track the configured scale too.
- Normalize zoom (window basis) and move_cursor (screen basis) inputs and
rewrite their descriptions, alongside click/double_click/right_click/drag.
- Fix zoom on downscaled (Retina) windows: apply the get_window_state resize
ratio so the crop lands on the region the agent saw. Normalized mode only;
pixel-mode zoom unchanged.
All coordinate behavior stays gated on the normalized flag, so the default
(pixels) path is unchanged from upstream.
* chore(cua-driver): add upstream-sync script (git subtree unusable here)
`git subtree split --prefix=libs/cua-driver` hangs on a commit deep in
trycua/cua's history, so the subtree add/pull workflow isn't usable for
the vendored driver (and a pull would re-split + re-hang every time).
Add scripts/sync-from-upstream.sh instead: it git-diffs two upstream refs
(never walks the full history, so it dodges the hang), reprefixes the
libs/cua-driver delta to packages/cua-driver, and `git apply --reject`s it
on top of our local changes — conflicts land as *.rej for manual fixup.
Record the vendored version in .vendored-from and document the migration +
sync method in the design doc.
* chore(cua-driver): exclude vendored driver from qwen-code ESLint
The vendored packages/cua-driver tree carries upstream JS (e.g. the
test-harness Electron app) that doesn't follow qwen-code's lint rules and
fails CI. It is not a workspace package (no package.json) and is not
qwen-code TypeScript, so add it to eslint.config.js global ignores —
alongside packages/desktop/** — the standard treatment for vendored code.
* fix(cua-driver): let start_session revive an idle-reaped session
Ports the fix from upstream trycua/cua#2035 into the vendored driver.
When a session is reaped for idleness, a subsequent start_session with the
same id failed instead of resuming it. Revive the ended session in place so
the agent can continue rather than getting a hard error.
* fix(cua-driver): retry daemon socket writes on EAGAIN
Ports the fix from upstream trycua/cua#2036 into the vendored driver.
A non-blocking daemon socket can return EAGAIN/EWOULDBLOCK mid-write when the
peer's receive buffer is momentarily full. The driver treated that as fatal
and dropped the connection. Add a bounded retry/poll loop (mirror of the
read-side socket_io helper) so transient back-pressure no longer kills the
session; only a real timeout or hard error fails the write.
* fix(cua-driver/linux): stop reporting bare "Clicked" for X11 synthetic clicks
Ports the fix from upstream trycua/cua#2025 into the vendored driver.
On X11, clicks are delivered via XSendEvent synthetic events, which many
toolkits (GTK/SDL/Allegro) ignore because send_event is set. The driver still
reported a flat success ("Clicked"), masking that nothing happened. Report
the synthetic-delivery caveat honestly so the agent can fall back instead of
assuming the click landed.
(platform-linux crate is not built on macOS; verified by clean upstream apply
and covered by upstream + release-workflow Linux CI.)
* fix(cua-driver/windows): list empty-/null-title top-level windows
Ports the fix from upstream trycua/cua#2021 into the vendored driver.
list_windows filtered out any top-level window whose title was empty or null,
so legitimate targets (splash screens, some Electron/game windows, tool
windows) were invisible to the agent and unclickable. Include empty-title
windows, using class name / process as a fallback label.
(platform-windows crate is not built on macOS; verified by clean upstream
apply and covered by upstream + release-workflow Windows CI.)
* chore(cua-driver): track cherry-picked upstream PRs; fix vendored-from
The vendored copy is actually at cua-driver-rs-v0.6.7 (workspace version and
all 0.6.7->0.6.8 delta files confirm it), but .vendored-from had drifted to
0.6.8 during an earlier sync-script trial whose code delta was not kept. Left
as-is it would make a future sync diff 0.6.8->newer and silently skip the real
0.6.7->0.6.8 fixes. Correct it back to 0.6.7.
Also record the four not-yet-merged upstream PRs we carry as cherry-picks
(trycua/cua#2021/#2025/#2035/#2036) in .vendored-patches.md, and have
sync-from-upstream.sh point at it so the next sync reconciles them.
* ci(cua-driver): satisfy repo yamllint on the release workflow
The vendored-driver release workflow tripped 114 quoted-strings violations
under the repo's .yamllint (quote-type: single, required). Single-quote all
string scalars to match every other workflow in .github/workflows.
While reformatting, the release-notes body also got its paragraph blank lines
collapsed and still referenced the old CUA_DRIVER_RS_COORDINATE_SPACE=
normalized_1000 value — restore the blank lines and update it to the current
0/1 toggle (default 0 = off; optional CUA_DRIVER_RS_COORDINATE_SCALE=1000).
* chore(cua-driver): sync vendored driver to cua-driver-rs-v0.6.8
First real run of scripts/sync-from-upstream.sh: it 3-way-applied the upstream
0.6.7->0.6.8 delta onto our local fork. 10/12 files applied cleanly; the 2
rejects (install.ps1, _install-rust.sh) were already-applied baked-version
bumps (0.6.6->0.6.7, our copies were already at 0.6.7), i.e. no real conflict.
0.6.8 brings: Wayland input path (platform-linux), linux health_report +
overlay tweaks, a platform-macos build.rs step, and dependency bumps. Version
moved to 0.6.8 across the workspace.
Verified our work survived the sync untouched: the relative-coordinate shim
(coord_norm/protocol) and all four cherry-picked PRs (socket_io/session +
linux/windows) are intact — in particular the 0.6.8 edit to platform-linux
tools/impl_.rs landed alongside our #2025 change with no collision. macOS
cargo check + 132 core tests green. (platform-linux/windows + the binary
integration test build only on their own runners; upstream CI covers those.)
* ci(cua-driver): add a dry_run gate to the release workflow
Mirror the desktop-release / release dry-run pattern: a workflow_dispatch
dry_run boolean input (default true). The cross-platform build + package jobs
always run and upload their artifacts; the GitHub Release job now publishes
only on a tag push or an explicit dry_run=false dispatch.
Lets us rehearse the whole build/package pipeline (dry_run=true, notarize=false)
and inspect the produced artifacts without cutting a release. A branch push
(no tag, not a dispatch) likewise builds without releasing.
375 lines
17 KiB
PowerShell
375 lines
17 KiB
PowerShell
# cua-driver-rs local installer (Windows). Builds release-mode from the
|
|
# current source tree and drops the resulting cua-driver.exe into the same
|
|
# install layout that scripts/install.ps1 produces — so a local build and
|
|
# a release install can coexist + the `current` junction can flip between
|
|
# them.
|
|
#
|
|
# Params mirror scripts/install.ps1 so the developer loop matches what
|
|
# end users experience:
|
|
# -AutoStart register the cua-driver-serve Scheduled Task at logon
|
|
# (Windows-native equivalent of macOS LaunchAgent).
|
|
# Default off; the post-install message prints the
|
|
# registration recipe so you can opt in later.
|
|
# -NoPathUpdate skip the auto-append of the bin dir to the User PATH.
|
|
# Mirrors install.ps1's flag.
|
|
#
|
|
# Always builds in `release` configuration to match what install.ps1
|
|
# hands users (the prebuilt zip from GitHub Releases is `--release`).
|
|
# Use `cargo build -p cua-driver` directly + invoke target\debug\cua-driver.exe
|
|
# if you specifically want a faster-to-compile debug binary.
|
|
#
|
|
# Not for end-users — `irm https://.../install.ps1 | iex` fetches a
|
|
# signed/built release from GitHub. This script is for the developer
|
|
# loop (rapid edit/build/test on a Windows host).
|
|
#
|
|
# Layout produced (matches install.ps1 — see its header for details):
|
|
#
|
|
# <visibleBinDir> [junction → currentDir]
|
|
# <currentDir> [junction → release dir, retargeted here]
|
|
# <release dir> [real dir, this script's output]
|
|
# 0.0.0-local-release-<target>\cua-driver.exe
|
|
#
|
|
# The version-string carries `-local-release` so it never collides with
|
|
# a real release dir and is trivial to garbage-collect.
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
# Default-on: most users want the daemon to come back at every
|
|
# logon. Opt out with `-AutoStart:$false` (or the dedicated
|
|
# `-NoAutoStart`) when running install-local.ps1 from CI / a
|
|
# container build / a sandbox where you specifically don't want
|
|
# a scheduled task registered.
|
|
[switch]$AutoStart = $true,
|
|
[switch]$NoAutoStart,
|
|
[switch]$NoPathUpdate
|
|
)
|
|
# `-NoAutoStart` is the explicit opt-out; takes precedence over the
|
|
# default-true `-AutoStart` for callers who'd rather read negative
|
|
# than `-AutoStart:$false`.
|
|
if ($NoAutoStart) { $AutoStart = $false }
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
$ProgressPreference = "SilentlyContinue"
|
|
|
|
# Reuse the production installer's helpers (path resolution, junction
|
|
# wiring, autostart registration) by dot-sourcing the relevant bits via
|
|
# a small wrapper. install.ps1 expects to run end-to-end, so we don't
|
|
# dot-source the whole thing — instead duplicate the small handful of
|
|
# operations we need, calling out matching install.ps1 functions where
|
|
# the logic would otherwise drift.
|
|
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
# Rust workspace root: scripts/ is the cross-cutting installer dir at
|
|
# libs/cua-driver/scripts/; the Cargo workspace lives one level deeper
|
|
# under libs/cua-driver/rust/.
|
|
$RepoRoot = (Resolve-Path "$ScriptDir\..\rust").Path
|
|
$BinaryName = "cua-driver.exe"
|
|
# Always release-config — matches the binary install.ps1 hands end users.
|
|
$Config = "release"
|
|
# Arch detection — use $env:PROCESSOR_ARCHITECTURE rather than
|
|
# RuntimeInformation::OSArchitecture so this works under
|
|
# Set-StrictMode -Version Latest (same fix as install.ps1 PR #1631).
|
|
$archEnv = $env:PROCESSOR_ARCHITECTURE
|
|
$Target = switch -Regex ($archEnv) {
|
|
'^ARM64$' { "aarch64-pc-windows-msvc"; break }
|
|
default { "x86_64-pc-windows-msvc" }
|
|
}
|
|
|
|
# ---------- Paths (must match install.ps1's defaults) ----------------------
|
|
|
|
if ($env:CUA_DRIVER_RS_INSTALL_DIR) {
|
|
$VisibleBinDir = $env:CUA_DRIVER_RS_INSTALL_DIR
|
|
} else {
|
|
# Path layout matches install.ps1's v0.2.14+ rename
|
|
# (trycua\cua-driver-rs → Cua\cua-driver). See PR #1644.
|
|
$VisibleBinDir = Join-Path $env:LOCALAPPDATA "Programs\Cua\cua-driver\bin"
|
|
}
|
|
if ($env:CUA_DRIVER_RS_HOME) {
|
|
$PackageHome = $env:CUA_DRIVER_RS_HOME
|
|
} else {
|
|
$PackageHome = Join-Path $env:USERPROFILE ".cua-driver"
|
|
}
|
|
$CurrentDir = Join-Path $PackageHome "packages\current"
|
|
$ReleasesDir = Join-Path $PackageHome "packages\releases"
|
|
|
|
# ---------- Helpers (mirror install.ps1) ----------------------------------
|
|
#
|
|
# install.ps1 keeps these inline in its own scope (it's a one-shot script
|
|
# that runs end-to-end). Mirror them here so install-local.ps1 can stand
|
|
# alone too. If install.ps1 ever extracts these into a shared file, this
|
|
# duplication is the time to delete it.
|
|
|
|
function Test-IsJunction([string]$path) {
|
|
if (-not (Test-Path -LiteralPath $path)) { return $false }
|
|
$item = Get-Item -LiteralPath $path -Force
|
|
return [bool]($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint)
|
|
}
|
|
|
|
function Ensure-Junction([string]$linkPath, [string]$targetPath) {
|
|
New-Item -ItemType Directory -Path (Split-Path -Parent $linkPath) -Force | Out-Null
|
|
if (Test-Path -LiteralPath $linkPath) {
|
|
if (Test-IsJunction $linkPath) {
|
|
# Always retarget — that's the point of this helper.
|
|
cmd /c rmdir (Resolve-Path -LiteralPath $linkPath).Path | Out-Null
|
|
} else {
|
|
throw "Refusing to replace non-junction at $linkPath. Move or delete it first."
|
|
}
|
|
}
|
|
cmd /c mklink /J $linkPath $targetPath | Out-Null
|
|
}
|
|
|
|
function Register-CuaDriverAutostart {
|
|
param([Parameter(Mandatory = $true)][string]$InstalledBinary)
|
|
if (-not (Test-Path -LiteralPath $InstalledBinary)) {
|
|
throw "binary not found at $InstalledBinary"
|
|
}
|
|
& $InstalledBinary autostart enable
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "cua-driver autostart enable failed (exit $LASTEXITCODE)"
|
|
}
|
|
}
|
|
|
|
# Stop-CuaDriverDaemons + Show-CuaDriverDaemonSurvivors are defined in
|
|
# the sibling _install-common.psm1 module - shared with install.ps1
|
|
# so the daemon-cleanup logic stays in one place. Local dev runs from
|
|
# a checked-out tree, so we always have the file on disk.
|
|
Import-Module -Name (Join-Path $ScriptDir "_install-common.psm1") -Force
|
|
|
|
function Write-Step($msg) { Write-Host "==> $msg" -ForegroundColor Cyan }
|
|
|
|
# ---------- Prerequisites --------------------------------------------------
|
|
|
|
Write-Step "cua-driver-rs local installer (Windows)"
|
|
Write-Host " source: $RepoRoot"
|
|
Write-Host " config: $Config"
|
|
Write-Host " target: $Target"
|
|
Write-Host " visible: $VisibleBinDir"
|
|
Write-Host " current: $CurrentDir"
|
|
|
|
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
|
|
Write-Host "Error: cargo not found on PATH." -ForegroundColor Red
|
|
Write-Host "Install Rust + MSVC toolchain via rustup-init: https://rustup.rs/"
|
|
exit 1
|
|
}
|
|
|
|
# ---------- Build ----------------------------------------------------------
|
|
|
|
Write-Step "cargo build --release -p cua-driver"
|
|
Push-Location $RepoRoot
|
|
try {
|
|
& cargo build --release -p cua-driver
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Host "Error: cargo build failed." -ForegroundColor Red
|
|
exit $LASTEXITCODE
|
|
}
|
|
}
|
|
finally {
|
|
Pop-Location
|
|
}
|
|
$BuiltBinary = Join-Path $RepoRoot "target\$Config\$BinaryName"
|
|
if (-not (Test-Path -LiteralPath $BuiltBinary)) {
|
|
Write-Host "Error: build produced no binary at $BuiltBinary" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# ---------- Stage into versioned release dir -------------------------------
|
|
|
|
$VersionTag = "0.0.0-local-$Config"
|
|
$VersionedDir = Join-Path $ReleasesDir "$VersionTag-$Target"
|
|
$DestBinary = Join-Path $VersionedDir $BinaryName
|
|
|
|
# If a previous install-local left a binary here and it's currently
|
|
# being executed (typical: `cua-driver autostart kick` spawned a
|
|
# High-IL daemon at logon, which we can't terminate from this
|
|
# Medium-IL shell without UAC), the Copy-Item below fails with
|
|
# "The process cannot access the file ... because it is being used by
|
|
# another process." Windows DOES allow renaming a locked .exe — the
|
|
# loader opens images with FILE_SHARE_DELETE, so a rename succeeds
|
|
# while the content stays locked. Renaming out of the way frees up
|
|
# the destination path so Copy-Item lands cleanly. The old file gets
|
|
# unlinked at the next reboot or when the daemon exits.
|
|
if (Test-Path -LiteralPath $DestBinary) {
|
|
$ts = (Get-Date).ToString('yyyyMMdd-HHmmss')
|
|
$stale = "$DestBinary.stale-$ts"
|
|
try {
|
|
Move-Item -LiteralPath $DestBinary -Destination $stale -Force -ErrorAction Stop
|
|
Write-Step "renamed locked previous binary to $(Split-Path -Leaf $stale)"
|
|
} catch {
|
|
Write-Host "Note: could not rename previous binary at $DestBinary." -ForegroundColor Yellow
|
|
Write-Host " ($($_.Exception.Message))" -ForegroundColor Yellow
|
|
Write-Host " Most likely a running cua-driver daemon is holding it." -ForegroundColor Yellow
|
|
Write-Host " Stop it first (e.g. ``schtasks /End /TN cua-driver-serve`` then re-run)." -ForegroundColor Yellow
|
|
}
|
|
# Best-effort GC of stale-* siblings older than this run. Cheap;
|
|
# keeps the dir from growing unbounded over many re-builds.
|
|
Get-ChildItem -LiteralPath $VersionedDir -Filter "$BinaryName.stale-*" -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
|
|
ForEach-Object { try { Remove-Item -LiteralPath $_.FullName -Force -ErrorAction SilentlyContinue } catch {} }
|
|
|
|
Write-Step "killing previous cua-driver processes (best-effort; High-IL needs admin)"
|
|
# Repair- variant does Stop-CuaDriverDaemonsWithHealth + stale
|
|
# detection + UAC self-elevation when wedged: if survivors are
|
|
# present AND the pipe is dead, prompts the user (y/n), and on
|
|
# yes triggers a UAC prompt to spawn a brief elevated
|
|
# PowerShell that kills the High-IL pids and re-runs the
|
|
# scheduled task. On UAC accept + healthy pipe afterward, the
|
|
# install proceeds at Medium IL like nothing happened. On UAC
|
|
# cancel / failure, falls back to the same printed manual
|
|
# recovery instructions the previous flow used.
|
|
$null = Repair-CuaDriverStaleDaemon
|
|
}
|
|
|
|
Write-Step "staging into $VersionedDir"
|
|
New-Item -ItemType Directory -Path $VersionedDir -Force | Out-Null
|
|
Copy-Item -LiteralPath $BuiltBinary -Destination $DestBinary -Force
|
|
$installedBinary = $DestBinary
|
|
|
|
# Stage the skill pack alongside the binary. install-local mirrors what
|
|
# install.ps1 does from a release zip — copies Skills/cua-driver-rs/ from
|
|
# the repo into the versioned dir so the `current` junction below
|
|
# transparently exposes it to agents.
|
|
$SourceSkills = Join-Path $RepoRoot "Skills\cua-driver-rs"
|
|
if (Test-Path -LiteralPath $SourceSkills) {
|
|
$StagedSkills = Join-Path $VersionedDir "Skills\cua-driver-rs"
|
|
if (Test-Path -LiteralPath $StagedSkills) {
|
|
Remove-Item -LiteralPath $StagedSkills -Recurse -Force
|
|
}
|
|
New-Item -ItemType Directory -Path (Split-Path -Parent $StagedSkills) -Force | Out-Null
|
|
Copy-Item -Path $SourceSkills -Destination $StagedSkills -Recurse -Force
|
|
Write-Step "staged skill pack at $StagedSkills"
|
|
}
|
|
|
|
# ---------- Repoint junctions ---------------------------------------------
|
|
|
|
Write-Step "retargeting $CurrentDir -> $VersionedDir"
|
|
Ensure-Junction -linkPath $CurrentDir -targetPath $VersionedDir
|
|
|
|
Write-Step "ensuring $VisibleBinDir -> $CurrentDir"
|
|
if (Test-Path -LiteralPath $VisibleBinDir) {
|
|
if (-not (Test-IsJunction $VisibleBinDir)) {
|
|
Write-Host "$VisibleBinDir exists and is not a junction; aborting." -ForegroundColor Red
|
|
Write-Host "Remove or relocate it, then re-run."
|
|
exit 1
|
|
}
|
|
}
|
|
Ensure-Junction -linkPath $VisibleBinDir -targetPath $CurrentDir
|
|
|
|
# ---------- User PATH update (matches install.ps1) ------------------------
|
|
|
|
if (-not $NoPathUpdate) {
|
|
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
$alreadyOnPath = $userPath -and (($userPath -split ';') -contains $VisibleBinDir)
|
|
if (-not $alreadyOnPath) {
|
|
$newValue = if ($userPath) { ($userPath.TrimEnd(';')) + ';' + $VisibleBinDir } else { $VisibleBinDir }
|
|
[Environment]::SetEnvironmentVariable('Path', $newValue, 'User')
|
|
# Also update the current process's $env:Path so subsequent
|
|
# commands in THIS shell see cua-driver immediately. install.ps1
|
|
# does the same — see #1651.
|
|
if (-not (($env:Path -split ';') -contains $VisibleBinDir)) {
|
|
$env:Path = "$VisibleBinDir;$env:Path"
|
|
}
|
|
Write-Step "added $VisibleBinDir to User PATH"
|
|
} else {
|
|
Write-Step "$VisibleBinDir already on User PATH"
|
|
}
|
|
} else {
|
|
Write-Step "skipping User PATH update (-NoPathUpdate)"
|
|
}
|
|
|
|
# Agent skill pack symlinks: NOT auto-created. Run
|
|
# `cua-driver skills install --local` to symlink agent dirs to the
|
|
# staged copy at $StagedSkills above.
|
|
|
|
# ---------- Done -----------------------------------------------------------
|
|
|
|
Write-Host ""
|
|
Write-Step "installed"
|
|
Write-Host " exe: $(Join-Path $VisibleBinDir $BinaryName)"
|
|
Write-Host " source: $installedBinary"
|
|
Write-Host ""
|
|
|
|
if ($AutoStart) {
|
|
Write-Step "registering Scheduled Task 'cua-driver-serve'"
|
|
try {
|
|
Register-CuaDriverAutostart -InstalledBinary (Join-Path $VisibleBinDir $BinaryName)
|
|
Write-Host " Registered. cua-driver serve auto-starts at every interactive logon." -ForegroundColor Green
|
|
}
|
|
catch {
|
|
Write-Host " Failed to register: $($_.Exception.Message)" -ForegroundColor Red
|
|
}
|
|
} else {
|
|
# User didn't pass -AutoStart, but if a `cua-driver-serve` task is
|
|
# ALREADY registered (from a previous `install.ps1 -AutoStart` or
|
|
# `cua-driver autostart enable`), re-register it pointing at this
|
|
# fresh binary. Otherwise the user ends up with a task whose
|
|
# <Command> path is the OLD release-install dir, running the OLD
|
|
# binary - even though `cua-driver` on PATH now resolves to the
|
|
# fresh one. See trycua/cua#1654 (hidden-console wrapper landed
|
|
# later - old tasks that survived an upgrade still produce the
|
|
# visible console window at logon).
|
|
$prevEAP = $ErrorActionPreference
|
|
$ErrorActionPreference = 'Continue'
|
|
try {
|
|
& schtasks.exe /Query /TN "cua-driver-serve" 2>$null | Out-Null
|
|
$hasTask = ($LASTEXITCODE -eq 0)
|
|
} finally {
|
|
$ErrorActionPreference = $prevEAP
|
|
}
|
|
if ($hasTask) {
|
|
Write-Step "found existing 'cua-driver-serve' task - re-registering against fresh binary"
|
|
try {
|
|
Register-CuaDriverAutostart -InstalledBinary (Join-Path $VisibleBinDir $BinaryName)
|
|
Write-Host " Re-registered. Task action now uses this build's hidden-console wrapper." -ForegroundColor Green
|
|
}
|
|
catch {
|
|
Write-Host " Failed to re-register: $($_.Exception.Message)" -ForegroundColor Red
|
|
Write-Host " The existing task still points at the previous binary. Run 'cua-driver autostart enable' from an elevated shell to update."
|
|
}
|
|
}
|
|
}
|
|
|
|
# Unified post-install hints come from a single shared text file so the
|
|
# 4 Rust installers (this script + install-local.sh + install.ps1 +
|
|
# _install-rust.sh) never drift. The .txt holds the OS-agnostic bulk
|
|
# (Try-it / skill pack / MCP setup / docs link) with {{BINARY}}
|
|
# placeholders; OS-specific bits stay inline below.
|
|
$installedBinary = Join-Path $VisibleBinDir $BinaryName
|
|
$HintsTxt = Join-Path $ScriptDir "post-install-hints.txt"
|
|
if (Test-Path -LiteralPath $HintsTxt) {
|
|
# Read explicitly as UTF-8. PowerShell 5.1's Get-Content -Raw falls
|
|
# back to Windows-1252 when the source file has no BOM, which turns
|
|
# the .txt's `•` / `—` into mojibake (`•` / `â€"`) in the rendered
|
|
# block. The other 3 installers don't hit this: install.ps1 reads
|
|
# the URL response via Invoke-WebRequest (HTTP charset decoding);
|
|
# _install-rust.sh / install-local.sh stream raw bytes through sed.
|
|
$hintsRaw = [System.IO.File]::ReadAllText($HintsTxt, [System.Text.Encoding]::UTF8)
|
|
Write-Host ($hintsRaw -replace '\{\{BINARY\}\}', $installedBinary)
|
|
} else {
|
|
# Repo layout changed or .txt missing — fall back to one-line
|
|
# essentials so users still know what to do next.
|
|
Write-Host "Next steps: $installedBinary --version | $installedBinary mcp-config | $installedBinary skills install"
|
|
Write-Host "Docs: https://github.com/trycua/cua/tree/main/libs/cua-driver/rust"
|
|
}
|
|
|
|
# Windows-specific autostart hint (kept inline; per-shell natural location).
|
|
if ($AutoStart) {
|
|
# Default branch: autostart was enabled (either by default or explicitly).
|
|
# Surface the management subcommands so the user knows how to inspect /
|
|
# disable later without digging through Task Scheduler.
|
|
Write-Host ""
|
|
Write-Host "Auto-start: 'cua-driver-serve' is registered at RunLevel=Highest." -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart status (inspect)" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart disable (remove)" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart kick (start now without re-logging)" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
} else {
|
|
# Opt-out branch (-NoAutoStart or -AutoStart:`$false`).
|
|
Write-Host ""
|
|
Write-Host "Auto-start at logon (NOT enabled - re-run without -NoAutoStart to register, or:):" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart enable (register Scheduled Task at RunLevel=Highest)" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart kick (start now without re-logging)" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart status (inspect)" -ForegroundColor Cyan
|
|
Write-Host " cua-driver autostart disable (remove)" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
}
|