feat(cua-driver): autostart {enable|disable|status|kick} CLI verb (Windows) - #1550
Conversation
…ndows)
New subcommand that registers / inspects / triggers a logon-time
Scheduled Task for `cua-driver serve` — the Windows-native equivalent
of the macOS LaunchAgent install.sh registers. Lives in
crates/cua-driver/src/autostart.rs and shells to PowerShell's
Register-ScheduledTask + schtasks.exe under the hood (mirroring
install.ps1 exactly so the two stay in lock-step).
Four subcommands:
cua-driver autostart enable Register the Scheduled Task with
LogonType=Interactive so it lands in
a Session 1+ logon (never Session 0).
Idempotent — replaces any existing
entry of the same name.
cua-driver autostart disable Unregister. No-op if the entry is
already absent ("does not exist" /
"cannot find the file specified"
schtasks.exe messages are mapped to
success because the goal is
"no entry registered").
cua-driver autostart status Emits one of:
not-registered
registered (not running)
registered (running)
The "running" check reuses the
daemon's own is_daemon_listening
probe against \\.\pipe\cua-driver —
no `tasklist` round-trip.
cua-driver autostart kick schtasks /Run /TN cua-driver-serve.
Brings the daemon up for the current
session without re-logging.
macOS / Linux: stub implementations return a helpful error pointing
the user at `scripts/install-local.sh --autostart` (which already
writes a LaunchAgent plist on macOS and a systemd --user unit on
Linux). A cross-platform native impl is tracked as a follow-up.
Telemetry: a new event `cua_driver_autostart_<sub>` fires on every
invocation (per-subcommand split so PostHog can show enable vs
disable adoption separately). The `<sub>` segment is normalised via
the existing sanitize_tool_name helper.
install.ps1 + install-local.ps1: the local Register-CuaDriverAutostart
helper is reduced to `& $exe autostart enable` (4 lines). The
post-install hint message now points at the verb instead of a
multi-line PowerShell recipe. One source of truth for the
registration logic, in Rust, where it can be unit-tested if needed.
Validated end-to-end on Win11 VM:
status (clean) -> not-registered
enable -> Registered autostart entry 'cua-driver-serve'
status -> registered (not running)
kick -> Started... + daemon listening
status -> registered (running)
disable -> Removed autostart entry
disable (again) -> Removed autostart entry (no-op)
enable -> Registered autostart entry
schtasks /Query -> Logon Mode: Interactive only, Run As User: ...
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR introduces a new ChangesWindows Autostart Command Implementation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 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)
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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
libs/cua-driver-rs/scripts/install.ps1 (1)
1-1:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSave this script with UTF-8 BOM to satisfy analyzer and avoid Unicode rendering issues.
Static analysis flagged missing BOM encoding for this Unicode script file.
🤖 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-rs/scripts/install.ps1` at line 1, The PowerShell installer script (libs/cua-driver-rs/scripts/install.ps1) must be saved with a UTF-8 BOM to satisfy the static analyzer and avoid Unicode rendering issues; reopen the file in your editor/IDE or use your commit tool to re-save the file encoding as "UTF-8 with BOM" (UTF-8 with signature) and recommit so the analyzer recognizes the BOM for this installer script.libs/cua-driver-rs/scripts/install-local.ps1 (1)
1-1:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSave this script with UTF-8 BOM to satisfy analyzer and avoid Unicode rendering issues.
Static analysis flagged missing BOM encoding for this Unicode script file.
🤖 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-rs/scripts/install-local.ps1` at line 1, The script header "# cua-driver-rs local/debug installer (Windows)." is missing a UTF-8 BOM; save the file using UTF-8 with BOM encoding so the static analyzer and Windows tools correctly recognize the Unicode text. Open the file in your editor or CI step and re-save with "UTF-8 with BOM" (or run a conversion tool to prepend the UTF-8 byte-order-mark) and commit the re-encoded file so the analyzer no longer flags the missing BOM.
🤖 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-rs/crates/cua-driver/src/autostart.rs`:
- Around line 183-185: In status(), don't treat every non-success exit from the
schtasks /Query command as Status::NotRegistered; instead mirror the disable()
logic by inspecting out.stderr/out.stdout for the "not found" messages (e.g.
"does not exist", "cannot find the file specified", "the system cannot find")
and only return Ok(Status::NotRegistered) when one of those substrings is
present; for other non-zero exits return an Err with the command output/error so
callers can distinguish permission/tool/runtime failures from a genuine missing
task (refer to the status() function and the existing disable() error-parsing
logic to copy the same message checks and error-return behavior).
- Around line 119-123: The scheduled task script builds the user identity using
$env:COMPUTERNAME\$env:USERNAME which breaks for domain accounts; update the
$user construction used by New-ScheduledTaskTrigger (-User) and
New-ScheduledTaskPrincipal (-UserId) to use $env:USERDOMAIN with a fallback to
$env:COMPUTERNAME when USERDOMAIN is empty or equals the local machine, so the
$user value becomes DOMAIN\USERNAME for domain-joined machines and
COMPUTERNAME\USERNAME for standalone hosts; apply this change where $user is
defined and used in the New-ScheduledTaskTrigger and New-ScheduledTaskPrincipal
invocations.
In `@libs/cua-driver-rs/scripts/install.ps1`:
- Around line 904-907: The Write-Host command examples that print invocations
using $installedBinary should show a quoted, invocable form so paths with spaces
work; update the examples that print "$installedBinary autostart kick",
"$installedBinary autostart status", and "$installedBinary autostart disable" to
use the PowerShell invocation form & "$installedBinary" (e.g., &
"$installedBinary" autostart kick) so consumers copy a safe, quoted command;
edit the Write-Host calls that reference $installedBinary accordingly.
---
Outside diff comments:
In `@libs/cua-driver-rs/scripts/install-local.ps1`:
- Line 1: The script header "# cua-driver-rs local/debug installer (Windows)."
is missing a UTF-8 BOM; save the file using UTF-8 with BOM encoding so the
static analyzer and Windows tools correctly recognize the Unicode text. Open the
file in your editor or CI step and re-save with "UTF-8 with BOM" (or run a
conversion tool to prepend the UTF-8 byte-order-mark) and commit the re-encoded
file so the analyzer no longer flags the missing BOM.
In `@libs/cua-driver-rs/scripts/install.ps1`:
- Line 1: The PowerShell installer script
(libs/cua-driver-rs/scripts/install.ps1) must be saved with a UTF-8 BOM to
satisfy the static analyzer and avoid Unicode rendering issues; reopen the file
in your editor/IDE or use your commit tool to re-save the file encoding as
"UTF-8 with BOM" (UTF-8 with signature) and recommit so the analyzer recognizes
the BOM for this installer script.
🪄 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: 8eed1d0d-1434-4fac-bb0c-6d2b5de3f8ec
📒 Files selected for processing (5)
libs/cua-driver-rs/crates/cua-driver/src/autostart.rslibs/cua-driver-rs/crates/cua-driver/src/cli.rslibs/cua-driver-rs/crates/cua-driver/src/main.rslibs/cua-driver-rs/scripts/install-local.ps1libs/cua-driver-rs/scripts/install.ps1
| $user = "$env:COMPUTERNAME\$env:USERNAME" | ||
| $action = New-ScheduledTaskAction -Execute $env:CUA_DRIVER_AS_EXE -Argument 'serve' -WorkingDirectory $env:USERPROFILE | ||
| $trigger = New-ScheduledTaskTrigger -AtLogOn -User $user | ||
| $principal = New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Limited | ||
| $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit (New-TimeSpan -Hours 0) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check if the file exists and examine the relevant section
fd autostart.rs -t f | head -20Repository: trycua/cua
Length of output: 108
🏁 Script executed:
# Read the specific lines mentioned in the review
cat -n libs/cua-driver-rs/crates/cua-driver/src/autostart.rs | sed -n '115,130p'Repository: trycua/cua
Length of output: 1394
🌐 Web query:
Windows PowerShell scheduled task principal USERDOMAIN vs COMPUTERNAME username domain
💡 Result:
When configuring the UserId for a Windows Scheduled Task principal using PowerShell, the format depends on whether the account is a local user or a domain user [1]. For local accounts, you can use the local computer name or the reserved name "LOCALSERVICE" [2][3][4]. A common practice is to use the environment variable $env:COMPUTERNAME to specify the local domain/computer context (e.g., "$env:COMPUTERNAME$env:USERNAME") [5]. For domain accounts, you must use the format DOMAIN\Username [1]. The Task Scheduler API requires this specific syntax to correctly resolve the security principal [1]. Using other formats, such as User Principal Name (UPN) format (user@domain), may result in authentication errors or failures during task registration [6]. When writing these strings in PowerShell code, ensure you use a double backslash (\) if you are using an escape character context, or simply use a single backslash within a standard string to represent the separator between the domain/computer and the username [1]. Summary of best practices: - Local accounts: Use $env:COMPUTERNAME\Username or simply the username if the system can resolve it locally [5]. - Domain accounts: Use DOMAIN\Username [1]. - Avoid UPN format (user@domain) for the UserId parameter, as it is not consistently supported by the underlying Task Scheduler API [6].
Citations:
- 1: https://learn.microsoft.com/en-us/windows/win32/taskschd/principal
- 2: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtaskprincipal?view=windowsserver2022-ps
- 3: https://pdq.com/powershell/new-scheduledtaskprincipal
- 4: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtaskprincipal?view=windowsserver2025-ps
- 5: https://stackoverflow.com/questions/13965997/powershell-set-a-scheduled-task-to-run-when-user-isnt-logged-in
- 6: Task registration error when specifying UserId of format user@domain dahall/TaskScheduler#926
🌐 Web query:
New-ScheduledTaskTrigger -User parameter domain user format Windows PowerShell
💡 Result:
The New-ScheduledTaskTrigger cmdlet in Windows PowerShell does include a -User parameter [1][2]. This parameter is used to specify the identifier of the user for a trigger that starts a task when that specific user logs on [1][3]. When using the -User parameter, the expected format is a string representing the user's identifier [1][2]. In a Windows environment, this is typically provided in the format DOMAIN\Username or simply Username for local accounts [4]. It is important to note that the -User parameter is specifically associated with the -AtLogOn trigger [1][2]. To create a task that runs for a specific user, you generally use the New-ScheduledTaskPrincipal cmdlet to define the user context (the account under which the task runs) [4], while the -User parameter in New-ScheduledTaskTrigger defines the specific user logon event that initiates the task [1][2]. Example usage: $trigger = New-ScheduledTaskTrigger -AtLogOn -User "DOMAIN\Username" $action = New-ScheduledTaskAction -Execute "notepad.exe" $principal = New-ScheduledTaskPrincipal -UserId "DOMAIN\Username" Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "MyTask"
Citations:
- 1: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtasktrigger?view=windowsserver2022-ps
- 2: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtasktrigger?view=windowsserver2025-ps
- 3: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtasktrigger?view=winserver2012r2-ps&redirectedfrom=MSDN
- 4: https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtask?view=windowsserver2025-ps
🌐 Web query:
Windows PowerShell $env:USERDOMAIN environment variable exists when available
💡 Result:
The environment variable $env:USERDOMAIN is a standard Windows environment variable that is typically available in Windows PowerShell sessions [1][2][3]. It is automatically populated by the operating system for the current process, reflecting the domain name (or local computer name) of the user account under which the process is running [2][3][4]. Key points regarding its availability and use: 1. Availability: It is generally present in any standard Windows PowerShell session because PowerShell inherits the environment block of its parent process, which includes this variable [5][6][4]. 2. Reliability: While $env:USERDOMAIN is convenient for scripts, it is a read-write environment variable [7]. It can be modified within the current session or by a parent process, meaning it may not always reflect the actual domain of the user [7]. For security-sensitive operations or when absolute accuracy is required, it is recommended to use the.NET class [System.Security.Principal.WindowsIdentity]::GetCurrent or [System.Environment]::UserDomainName, which retrieve the information directly from the system and cannot be spoofed by modifying environment variables [1][7][3]. 3. Access: In PowerShell, you can access it using the $env: prefix (e.g.,
Citations:
- 1: https://stackoverflow.com/questions/2085744/how-do-i-get-the-current-username-in-windows-powershell/29955210
- 2: https://ss64.com/nt/syntax-variables.html
- 3: https://stackoverflow.com/questions/1607271/how-do-you-find-the-current-user-in-a-windows-environment
- 4: https://learn.microsoft.com/en-us/windows/win32/shell/user-environment-variables
- 5: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.6
- 6: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.4
- 7: https://stackoverflow.com/questions/58565296/why-would-envusername-and-environmentusername-return-different-users
- 8: https://stackoverflow.com/questions/76276480/use-environment-variables-to-identify-a-directory-in-powershell
Use domain-aware user identity when building the scheduled task principal.
At line 119, $env:COMPUTERNAME\$env:USERNAME fails for domain users. Domain-joined machines require the format DOMAIN\USERNAME for both the trigger's -User parameter (line 121) and the principal's -UserId parameter (line 122). Use $env:USERDOMAIN instead, with fallback to $env:COMPUTERNAME for standalone machines.
Proposed fix
-$user = "$env:COMPUTERNAME\$env:USERNAME"
+$domain = if ($env:USERDOMAIN) { $env:USERDOMAIN } else { $env:COMPUTERNAME }
+$user = "$domain\$env:USERNAME"🤖 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-rs/crates/cua-driver/src/autostart.rs` around lines 119 -
123, The scheduled task script builds the user identity using
$env:COMPUTERNAME\$env:USERNAME which breaks for domain accounts; update the
$user construction used by New-ScheduledTaskTrigger (-User) and
New-ScheduledTaskPrincipal (-UserId) to use $env:USERDOMAIN with a fallback to
$env:COMPUTERNAME when USERDOMAIN is empty or equals the local machine, so the
$user value becomes DOMAIN\USERNAME for domain-joined machines and
COMPUTERNAME\USERNAME for standalone hosts; apply this change where $user is
defined and used in the New-ScheduledTaskTrigger and New-ScheduledTaskPrincipal
invocations.
| if !out.status.success() { | ||
| return Ok(Status::NotRegistered); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the autostart.rs file
find . -name "autostart.rs" -type fRepository: trycua/cua
Length of output: 110
🏁 Script executed:
# Read the autostart.rs file to see the context around lines 183-185
cat -n libs/cua-driver-rs/crates/cua-driver/src/autostart.rs | head -200 | tail -50Repository: trycua/cua
Length of output: 2417
🏁 Script executed:
# Get more context around the schtasks command usage
rg -n "schtasks" libs/cua-driver-rs/crates/cua-driver/src/autostart.rs -B 5 -A 5Repository: trycua/cua
Length of output: 3209
🏁 Script executed:
# Search for how Status::NotRegistered is defined and used
rg -n "Status::" libs/cua-driver-rs/crates/cua-driver/src/autostart.rs | head -20Repository: trycua/cua
Length of output: 388
Match stderr/stdout against specific error messages in status() to distinguish task-not-found from other failures.
The schtasks /Query command at line 183 treats all non-zero exit codes as Status::NotRegistered, which masks permission denied, tooling, or runtime errors as a false "not registered" state. The comment at lines 177-178 acknowledges that exit code 1 specifically indicates "the system cannot find the file specified," but the code doesn't verify this message.
The codebase already handles this correctly in the disable() function (lines 147-174), which checks stderr/stdout for specific error strings ("does not exist", "cannot find the file specified", "the system cannot find") to distinguish legitimate "not found" failures from actual errors. Apply the same pattern here to return an error for unexpected failures while returning Status::NotRegistered only when the error message confirms the task does not exist.
🤖 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-rs/crates/cua-driver/src/autostart.rs` around lines 183 -
185, In status(), don't treat every non-success exit from the schtasks /Query
command as Status::NotRegistered; instead mirror the disable() logic by
inspecting out.stderr/out.stdout for the "not found" messages (e.g. "does not
exist", "cannot find the file specified", "the system cannot find") and only
return Ok(Status::NotRegistered) when one of those substrings is present; for
other non-zero exits return an Err with the command output/error so callers can
distinguish permission/tool/runtime failures from a genuine missing task (refer
to the status() function and the existing disable() error-parsing logic to copy
the same message checks and error-return behavior).
| Write-Host " Run now without re-logging: $installedBinary autostart kick" | ||
| Write-Host " Inspect: $installedBinary autostart status" | ||
| Write-Host " Remove: $installedBinary autostart disable" | ||
| Write-Host "" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify unquoted command hints in the installer output templates
rg -n '\$installedBinary autostart (enable|kick|status|disable)' libs/cua-driver-rs/scripts/install.ps1 -C 2Repository: trycua/cua
Length of output: 1174
Properly quote $installedBinary in command examples to handle paths with spaces.
Lines 904–907 and 921–924 display command examples without proper quoting. When the installed path contains spaces (e.g., in user profile directories), these commands fail. Use & "$installedBinary" syntax in PowerShell to correctly invoke the binary.
Proposed fix
- Write-Host " Run now without re-logging: $installedBinary autostart kick"
- Write-Host " Inspect: $installedBinary autostart status"
- Write-Host " Remove: $installedBinary autostart disable"
+ Write-Host " Run now without re-logging: & `"$installedBinary`" autostart kick"
+ Write-Host " Inspect: & `"$installedBinary`" autostart status"
+ Write-Host " Remove: & `"$installedBinary`" autostart disable"
@@
- Enable: $installedBinary autostart enable
- Run now: $installedBinary autostart kick
- Status: $installedBinary autostart status
- Remove: $installedBinary autostart disable
+ Enable: & "$installedBinary" autostart enable
+ Run now: & "$installedBinary" autostart kick
+ Status: & "$installedBinary" autostart status
+ Remove: & "$installedBinary" autostart disable🧰 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-rs/scripts/install.ps1` around lines 904 - 907, The
Write-Host command examples that print invocations using $installedBinary should
show a quoted, invocable form so paths with spaces work; update the examples
that print "$installedBinary autostart kick", "$installedBinary autostart
status", and "$installedBinary autostart disable" to use the PowerShell
invocation form & "$installedBinary" (e.g., & "$installedBinary" autostart kick)
so consumers copy a safe, quoted command; edit the Write-Host calls that
reference $installedBinary accordingly.
CR #1550 review feedback (both Major): 1. autostart.rs::REGISTER_PS hard-coded the principal as `$env:COMPUTERNAME\$env:USERNAME`. That works for workgroup machines (where USERDOMAIN equals "WORKGROUP" or COMPUTERNAME, neither of which resolves as a SAM principal) but breaks on domain-joined hosts where the principal must be `DOMAIN\username`. New domain selector prefers USERDOMAIN when it's a real third-party domain, falls back to COMPUTERNAME otherwise — covers both shapes. 2. install.ps1 post-install hint printed `$installedBinary autostart enable` as-is. If $installedBinary contains spaces (e.g. `C:\Program Files\...`) the resulting copy-paste fails PowerShell parsing. Wrap in `& "$installedBinary"` so the hint is copy-paste-safe regardless of install path.
Summary
New CLI verb
cua-driver autostart {enable|disable|status|kick}—the Windows-native equivalent of the macOS LaunchAgent that
install.shregisters. Single source of truth for the ScheduledTask registration logic; the install scripts now just shell out to
the verb.
cua-driver-serveScheduled Task withLogonType=Interactiveso it lands in Session 1+ (never Session 0).Idempotent — replaces any existing entry.
not-registered,registered (not running),registered (running). The "running" probe reusesis_daemon_listeningagainst\\.\pipe\cua-driver, notasklist.schtasks /Runso the daemon comes up for the currentsession without re-logging.
install.ps1andinstall-local.ps1now invokecua-driver autostart enableinstead of duplicating ~50 LOC of PowerShell. Their helpersare 4 lines each.
macOS / Linux: stub implementations point users at
install-local.sh --autostart(which already does the right thingon those platforms). Native impl for non-Windows is a follow-up.
Telemetry: per-subcommand events (
cua_driver_autostart_enable,_disable,_status,_kick) so adoption can be split on thePostHog dashboard.
Test plan
disable → disable (no-op) → enable, all green.
schtasks /Query /TN cua-driver-servereportsLogon Mode: Interactive onlyafter enable.with
statusreportingregistered (running)).install.ps1 -AutoStartend-to-end (not re-tested under thenew shell-out — would need a clean install to validate).
time only on this PR; no live test box).
Summary by CodeRabbit