name: uninstalling-the-extension description: "How WE (this repo) uninstall the Adom browser extension from the user's real Chrome/Edge, driving adom-desktop'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-browser-extension."

Part of adom-browser-extension. 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 adom-desktop's generic OS verbs (desktop_navigate, desktop_find_control, desktop_ui_click, desktop_ui_set, desktop_screenshot_window). AD 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-desktop 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.