feat(uninstall): opt-in removal of the VirtualHID driver (#679)#705
feat(uninstall): opt-in removal of the VirtualHID driver (#679)#705malpern wants to merge 1 commit into
Conversation
The user-facing uninstall already tears down the daemon, helper, and app, but left the Karabiner VirtualHID driver installed, and InstallerEngine.uninstall's `_ = broker // Reserved for future privileged uninstall steps` was an unused hook. Add an opt-in "Also remove the virtual keyboard driver" checkbox to the uninstall dialog (default off — VHID is a shared component other tools like Karabiner-Elements may rely on). The flag threads UninstallKeyPathDialog → KanataViewModel → RuntimeCoordinator → InstallerEngine.uninstall, which now uses the broker to call uninstallVirtualHIDDrivers() before the main teardown (that self-destructs the privileged helper this step depends on). Best-effort: a VHID failure logs and continues so it never blocks removing KeyPath itself. Manual verification needed: the uninstall path is destructive and can't be exercised in automated tests. Verify a real uninstall with the toggle on (driver removed) and off (driver preserved) before relying on it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — feat(uninstall): opt-in removal of the VirtualHID driverOverviewClean, minimal implementation. The flag threads cleanly through all four layers ( Issues & Suggestions1. Silent VHID failure not surfaced in the returned When Suggested fix — add the failure to the logs array that gets passed into the report: var extraLogs: [String] = []
if removeVirtualHID {
do {
try await broker.uninstallVirtualHIDDrivers()
AppLogger.shared.log("🗑️ [InstallerEngine] Virtual HID driver removed")
} catch {
let msg = "Virtual HID removal failed (driver may still be installed): \(error)"
AppLogger.shared.log("⚠️ [InstallerEngine] \(msg)")
extraLogs.append(msg)
}
}Then pass 2. UI shows "Uninstall Complete" even when VHID removal silently failed (medium) Following from #1: Consider displaying a soft warning (e.g., an inline 3. Unnecessary comment on line 40 of the dialog (minor) // Optional: also remove the shared Karabiner virtual keyboard driver.Per CLAUDE.md: "Only add [a comment] when the WHY is non-obvious." The toggle label already says what this does. The comment can be removed. 4. Not introduced by this PR, but worth noting: the dialog always passes What's Good
VerificationAuthor correctly flags this as requiring manual verification. Before merging, confirm:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93690c7c20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try await broker.uninstallVirtualHIDDrivers() | ||
| AppLogger.shared.log("🗑️ [InstallerEngine] Virtual HID driver removed") | ||
| } catch { | ||
| AppLogger.shared.log("⚠️ [InstallerEngine] Virtual HID removal failed (continuing uninstall): \(error)") |
There was a problem hiding this comment.
Route opted-in VHID removal through fallback path
When the privileged helper is missing or not responding, broker.uninstallVirtualHIDDrivers() fails in release because the router's privileged-helper branch only calls helperManager.uninstallVirtualHIDDrivers() (no sudo/script fallback), but the catch here swallows that failure and then the normal uninstall can still succeed via UninstallCoordinator's admin-prompt script fallback. In that scenario, a user who checked “Also remove the virtual keyboard driver” gets a successful uninstall while the VirtualHID driver is preserved, so this path needs either a fallback before continuing or a report that the opted-in removal did not happen.
Useful? React with 👍 / 👎.
Closes #679.
The user-facing uninstall already tears down the daemon, helper, and app, but left the Karabiner VirtualHID driver installed — and
InstallerEngine.uninstall's_ = broker // Reserved for future privileged uninstall stepswas an unused hook.Change
UninstallKeyPathDialog → KanataViewModel → RuntimeCoordinator → InstallerEngine.uninstall, which now uses the broker to calluninstallVirtualHIDDrivers()before the main teardown (that self-destructs the privileged helper this step depends on).The uninstall path is destructive and can't be exercised in automated tests. Before merging, please verify a real uninstall manually:
Not auto-merging for this reason.