Skip to content

feat: in-app Windows uninstall + App-section reorder/modal + Windows stop-exit reap#321

Merged
bilbospocketses merged 9 commits into
mainfrom
feat/app-section-redesign
Jun 8, 2026
Merged

feat: in-app Windows uninstall + App-section reorder/modal + Windows stop-exit reap#321
bilbospocketses merged 9 commits into
mainfrom
feat/app-section-redesign

Conversation

@bilbospocketses

Copy link
Copy Markdown
Owner

Implements the App-section redesign + in-app Windows uninstall (spec/plan: docs/{specs,plans}/2026-06-08-app-section-redesign-windows-uninstall*). Built TDD via subagent-driven development, each unit independently verified.

1. App-section reorder (both OS)

reset prompts -> install for all users (Linux) -> stop server & exit -> uninstall. install-for-all-users stays Linux-only; uninstall now shows on both OSes.

2. Uninstall confirm -> overlay modal (both OS)

Inline panel -> top-layer <dialog> (UninstallConfirmModal) with a keep my settings & logs checkbox (defaults to checked — the safe option) + white cancel / red uninstall buttons.

3. In-app Windows uninstall (NEW — parity with Linux)

The uninstall button now works on Windows: ServiceApi win32 branch -> a new launcher/src/windows_app_uninstall.rs helper (mirror of linux_app_uninstall.rs) -> Update.exe --uninstall (fires the existing --veloapp-uninstall hook: service + tray + ARP cleanup) + dataRoot keep/wipe (deps always gone; config + logs per the checkbox).

4. Fix Windows "stop server & exit" cleanup

  • The tray-supervisor poll thread is now stopped before the tray reap (it could otherwise respawn the tray the reap just killed).
  • gracefulShutdown now also runs taskkill /F /IM adb.exe /T to catch stray adb, mirroring the in-app update path.

Verification (unit-green)

tsc --noEmit exit 0; vitest 932 passed; launcher cargo test 108+1, clippy -D warnings clean.

VM-gated — settled on the Win11 smoke (Module 15 in smoke-full.md)

  • Does Update.exe --uninstall self-elevate when launched by the unelevated staged launcher (one UAC)? If not, route the Node spawn through the launcher's --request-uac seam (a new windows-app-uninstall command).
  • On wipe, does the dataRoot fully clear despite the running helper in control\operation-server\ (Windows can't delete a running exe)? If it orphans that dir, add a self-deleting step.
  • Update.exe --uninstall vs msiexec /x for a clean Add/Remove-Programs removal.

release:beta -> cuts beta.51 for the VM smoke.

…indows stop-exit tray + adb reap)

Adds the phased TDD plan (frontend reorder + modal, Rust windows_app_uninstall
helper + ServiceApi win32 branch, tray-reap stop_flag, adb taskkill belt-and-braces)
and amends the spec with item 4 after verifying gracefulShutdown only kill-servers
adb on Windows (missing the taskkill the update path uses).
Part A: appSectionButtonsState now returns showUninstall = linux || win32,
so the uninstall row is revealed on Windows too. install-for-all-users
remains Linux-only (showInstallAllUsers unchanged). Updated doc-comment.

Part B: buildAppSection reorders body.appendChild calls so the DOM
top-to-bottom order is: reset (+ confirm panel) → install-for-all-users
(+ note) → stop server (+ note) → uninstall (+ confirm panel).
Construction code for each control is unchanged; only append sequence moved.

Tests: two new Part A assertions (win32 showUninstall=true,
showInstallAllUsers=false; linux both=true); one Part B DOM-order test
instantiating SettingsModal in jsdom and asserting label subsequence.
Updated the pre-existing win32 equality snapshot to reflect new behaviour.
Add UninstallConfirmModal (Modal subclass, static confirm() API) with
keep-my-settings checkbox defaulting checked and a red-outline uninstall
button (settings-btn-danger-outline). Rewire buildUninstallControl to open
the modal instead of toggling an inline confirm panel; remove the inline
panel, uninstallConfirmPanel field, and its collapse branch in
applyAppSectionButtonsState. Add .settings-btn-danger-outline CSS rule.
All changes TDD: tests written first, all 124 client tests green, tsc clean.
Pure builder `windows_app_uninstall_commands` + `parse_args` + `handle`
dispatcher mirroring linux_app_uninstall.rs. Invokes Update.exe --uninstall
(Velopack hook fires service/tray/ARP teardown), then removes dataRoot via
std::fs per keep/wipe scope. 17 unit tests; clippy clean.
POST /api/service/uninstall-app now spawns the staged operation-server
launcher with `--windows-app-uninstall --keep|--wipe --data-root <…>
--update-exe <installRoot>\Update.exe` on win32, mirroring the linux
branch (detached spawn, 200 { ok:true, status:'uninstalling' },
scheduleExit). Elevation is delegated to Update.exe (a PerMachine
install's Update.exe self-elevates via UAC) — the same elevation-lives-
in-the-launcher model as the §30 request-uac path; the spawn itself
stays unelevated.

The staged helper is resolved from <dataRoot>/control/operation-server
(Velopack-untouchable, survives Program Files removal); installRoot is
anchored at the webpack bundle location like UpdateService so Update.exe
resolves to the Velopack root (parent of current/). The unsupported
fallback now covers only non-win32/non-linux.
… on exit

D1: supervisor::run() now returns the tray-supervisor stop_flag alongside the
exit code. main.rs signals it (SeqCst store true) before calling
reap_tray_on_terminal_exit, preventing the 10s poll thread from respawning the
tray between the signal and the taskkill. Windows-only; non-Windows gets None.

D1b: gracefulShutdown() in index.ts now runs a win32-only
taskkill /F /IM adb.exe /T after adb kill-server, matching the belt-and-braces
pattern already present in UpdateService.preApplyHygiene. Extracted into
shutdownHelpers.ts (reapStrayAdbOnWindows) for testability; 3 unit tests cover
win32/non-win32 dispatch and no-match exit-code swallow.
CHANGELOG [Unreleased]: Added in-app Windows uninstall; Changed App-section
order + uninstall modal; Fixed Windows stop-exit tray + stray-adb reap.
smoke-full.md Module 15: Windows uninstall (keep/wipe) + stop-exit rows, with
the VM-gated elevation + running-helper self-deletion decisions flagged.
@bilbospocketses bilbospocketses added the release:beta Auto-release: bump to next beta on merge label Jun 8, 2026
@bilbospocketses bilbospocketses merged commit 3540650 into main Jun 8, 2026
9 checks passed
@bilbospocketses bilbospocketses deleted the feat/app-section-redesign branch June 8, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:beta Auto-release: bump to next beta on merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant