---
name: uninstalling-the-extension
description: "How WE (this repo) uninstall the Adom Native Browser Extension from the user's real Chrome/Edge, driving Bridge's GENERIC OS verbs - BACKGROUND-first, never stealing focus. Covers the critical safety guard (all \"Remove\" buttons share the same name, so filter the list to the Adom card first or you can remove the WRONG extension), the Remove-confirm bubble (a Chromium owned popup that needs ONE brief foreground beat because it dies on focus loss), verifying removal by screenshot AND by the nbrowser_ profile key dropping, and optional full cleanup (native-messaging host + bridge). Use when the user says \"uninstall the extension\", \"remove the Adom extension\", \"take it out of my browser\", \"reinstall it\" (uninstall then installing-the-extension). Low-level click mechanics: driving-the-desktop. Safety: native-browser-safety. Part of the adom-native-browser."
---
Part of **adom-native-browser**. Install: **installing-the-extension**. Low-level OS mechanics: **driving-the-desktop**. Safety: **native-browser-safety**.

# Uninstalling the extension - the orchestration WE own (background-first)

Like install, this is **our** recipe driving Bridge's **generic** OS verbs (`desktop_navigate`,
`desktop_find_control`, `desktop_ui_click`, `desktop_ui_set`, `desktop_screenshot_window`). ab has no
"uninstall extension" feature; we own the sequence and its safety.

## ⛔⛔ Two rules that make or break this
1. **Background-first, never force the foreground.** Focus theft is rude AND corrupts the flow: if the
   user keeps typing, their keystrokes land in the control you focused (the Search box), silently
   changing your filter and **hiding the card you were about to remove** (real case: search became
   `Adoms`, the Adom card vanished). Use background UIA (`desktop_ui_click` Invoke, `desktop_ui_set`
   SetValue), `desktop_screenshot_window` - none steal focus. There is exactly ONE unavoidable foreground
   beat (the confirm bubble, Step 3); narrate it and keep it to ~1s.
   - ⚠️ Foreground can happen even with NO `bring_to_front`: opening a window and **`desktop_navigate`**
     (omnibox commit) can surface the window despite `focused:false`. Judge by the **outcome** - check
     `desktop_list_windows` (`z:0` = topmost = you surfaced it). And screenshot-verify the page actually
     loaded (tab title "Extensions"), not just the omnibox URL; the posted-Enter sometimes needs a retry.
2. **Isolate the target or you may remove the WRONG extension.** On `chrome://extensions` every card's
   Remove button has the **same** accessible name "Remove" and `automationId:"removeButton"` - a blind
   `contains:"Remove"` is ambiguous. **Filter the list to just the Adom card first** (Step 2). Verify by
   screenshot that exactly one card shows before you trigger Remove.

## Step 1 - open chrome://extensions in YOUR OWN background window
```
nbrowser_open_window {sessionId:"uninstall", thread:"<you>", purpose:"driving chrome://extensions to remove the extension", profile, url:"about:blank"}   # your window; find its hwnd via desktop_list_windows (match a unique title)
desktop_navigate {hwnd:<W>, url:"chrome://extensions"}            # edge://extensions for Edge - scheme MUST match the browser
desktop_screenshot_window {hwnd:<W>}                              # read it: is the Adom card present?
```

## Step 2 - ISOLATE the Adom card (the safety guard)
Set the search box to the extension name so only the Adom card (and its Remove button) remains:
```
desktop_ui_set {hwnd:<W>, contains:"Search extensions", text:"Adom"}   # background SetValue; automationId "searchInput", settable
desktop_screenshot_window {hwnd:<W>}                                   # CONFIRM exactly one card shows ("Adom for Chrome & Edge")
```
⚠️ `ui_set` REPLACES the field - re-read the screenshot, because a stray prior value (or a focus-theft
keystroke) can leave junk like `Adoms` that matches nothing ("No search results found"). Fix it (set
again) before proceeding. Do not trigger Remove until the screenshot shows the single Adom card.

## Step 3 - Remove + confirm (the one brief, narrated foreground beat)
The confirm bubble (`Remove "Adom for Chrome & Edge"?`) is a Chromium **owned popup that dies on focus
loss**, so the window must hold focus across the trigger->confirm. This is the one place foreground is
unavoidable - so narrate it and do it fast, atomically, nothing in between:
```
desktop_caption {text:"Adom: removing the extension - one moment, please don't type"}
desktop_bring_to_front {hwnd:<W>}                                       # the ~1s foreground beat (unavoidable for the bubble)
desktop_ui_click {hwnd:<W>, contains:"Remove"}                          # trigger -> opens the bubble (unambiguous now, after Step 2)
# wait ~1s; do NOT insert a screenshot/find_control here - the bubble auto-closes in ~1-2s
desktop_ui_click {hwnd:<W>, scope:"popups", role:"button", name:"Remove"}   # confirm (background Invoke of the owned popup)
desktop_caption {text:""}                                               # clear the caption; return focus to the user
```
- `scope:"popups"` enumerates the window's owned, borderless popups (invisible to `desktop_list_windows`)
  and Invokes the bubble's "Remove". The bubble title is `Remove "<ext>" from <browser>?`.
- If you get `scope:popups found no owned/popup windows`, the bubble already closed (you were too slow or
  inserted a step) - just re-trigger and confirm immediately.
- **To CAPTURE the bubble for docs**, do a SEPARATE pass: trigger Remove, then `desktop_screenshot_window
  {hwnd:<W>}` - the bubble rides back in the response's `screenshots[]` array (saved as
  `popup-<hwnd>-<ts>.png`) since it is an owned popup. Then click Cancel (`scope:"popups"` ... name:"Cancel")
  instead of Remove. Don't try to screenshot mid-removal; the bubble dies before the confirm.

## Step 4 - verify it's gone (screenshot AND state)
1. **Screenshot:** `desktop_screenshot_window {hwnd:<W>}` - the Adom card is gone (the filtered list shows
   "No search results found", or the card is absent when unfiltered).
2. **State:** poll `nbrowser_profiles` / `nbrowser_status` - the `chrome:`/`edge:` profile key **drops**
   within ~1-2s as the service worker dies. (This is the authoritative signal it actually unloaded.)

## Cross-browser (Edge) and full cleanup
- **Edge:** identical, but `edge://extensions` (scheme must match) and verify the `edge:` key drops.
- **Just unloading vs full removal:** removing the card unloads the extension and drops the SW. To fully
  decommission (not just unload), also: remove the HKCU native-messaging host
  (`HKCU\Software\Google\Chrome\NativeMessagingHosts\inc.adom.native_browser`, and the Edge key), and if
  the user wants the bridge gone too, `adom-bridge-cli bridge_uninstall {name:"native-browser"}`. For a plain
  "take it out of my browser," Steps 1-4 are enough.

## Recovery
Reinstall with **installing-the-extension** (dev-mode Load unpacked). Removal + reinstall is also the
clean way to apply an updated `extension/` build.

## The one-line version
Open your own background window, filter to the Adom card so Remove is unambiguous, narrate the one ~1s
foreground beat the confirm bubble forces, atomically trigger->confirm, then verify by BOTH the
screenshot and the dropped `nbrowser_` profile key.
