# Browser extension — Tab Picker

Compare products straight from your open tabs instead of copy-pasting URLs. Click
the toolbar icon, tick the tabs you want (grouped by site, so Amazon links cluster
together), and hit **Compare** — the comparison tool opens with those URLs filled
in and, if your API key is already saved, runs automatically.

Works in **Chrome**, **Firefox**, and **Safari** from one source.

- **Installing it?** → [INSTALL.md](INSTALL.md) — step by step, no terminal needed.
- **Submitting it to a store?** → [PUBLISHING.md](PUBLISHING.md).

## Build

The extension reuses the comparison app at the repo root, so there's a one-line
assemble step (no dependencies — just `bash`, `sed`, and `zip`):

```sh
cd extensions
./build.sh
```

This writes the loadable folders `dist/chrome/` and `dist/firefox/`, plus a
submittable `dist/product-comparison-<browser>-<version>.zip` for each.

## Release

`./release.sh` publishes those zips as a GitHub release — the download
[INSTALL.md](INSTALL.md) sends people to. It builds fresh, runs the root tests, tags
the commit, and uploads both zips with a `SHA256SUMS.txt`:

```sh
cd extensions
./release.sh --dry-run     # see exactly what would be published
./release.sh               # release the version in src/manifest.chrome.json
./release.sh 1.1.0         # set that version in both manifests, commit, then release
```

Needs the [GitHub CLI](https://cli.github.com) logged in with write access. See
[PUBLISHING.md](PUBLISHING.md#github-release) for the details it enforces.

## Load it

- **Chrome / Edge / Brave** — go to `chrome://extensions`, enable *Developer mode*,
  click *Load unpacked*, and select `extensions/dist/chrome`.
- **Firefox** — go to `about:debugging#/runtime/this-firefox`, click *Load Temporary
  Add-on*, and select `extensions/dist/firefox/manifest.json`.
  (Temporary add-ons clear on restart; for a permanent install, sign the package
  with `web-ext` or submit it to AMO.)
- **Safari** — Safari can't load a raw folder; convert the Chrome build with Apple's
  tool (needs Xcode):
  ```sh
  xcrun safari-web-extension-converter extensions/dist/chrome
  ```
  Open the generated Xcode project, run it, then enable the extension in
  *Safari → Settings → Extensions*. (Enable *Develop → Allow Unsigned Extensions*
  for local use.)

## How it works

- `popup.html/.css/.js` — reads open tabs via the `tabs` permission, groups them by
  registrable domain, and lets you select. On **Compare**, it captures each selected
  tab's rendered text (and best product image) with `scripting.executeScript`, stashes
  them plus the URLs in `storage.local`, and opens the bundled comparison page.
- `prefill.js` — runs inside `app.html`, exposes the captured page content to the app
  (keyed by the app's normalized URL), fills the textarea, and starts the comparison
  if an API key is saved. On the plain web page it does nothing.
- `app.html` + `app.js` / `template.js` / `styles.css` — the same comparison tool
  from the repo root, copied in at build time (single source of truth).

### Reading pages your own browser can see

Extraction tries, in order: **(1)** the content captured from your open tab, **(2)**
Gemini's `url_context`, **(3)** the reader proxy. Step 1 is why the extension handles
sites that block servers — Amazon, **AliExpress**, and logged-in pages — because it
reads the real, rendered page already loaded in *your* browser. If a tab can't be
scripted, it silently falls back to steps 2–3.

Permissions: `tabs` (list tabs), `storage` (pass the selection), `scripting` +
`host_permissions: <all_urls>` (read the content of the tabs you pick). Page content
is used only locally to build the comparison — nothing is sent anywhere except the
Gemini/reader-proxy calls the app already makes.

### Host permissions are not equal across browsers

Chrome grants `host_permissions` at install time. **Firefox and Safari treat them as
opt-in**, so `scripting.executeScript` fails there until the user allows site access —
and because the failure is caught and falls through to the server-side path, the
extension would otherwise lose its main advantage in silence.

`popup.js` therefore checks `permissions.contains()` on open and shows a banner with
a **Grant access** button when access is missing. On Chrome the check passes and the
banner never appears. On Firefox the permission prompt closes the popup — reopening
it shows the banner gone.

## Source layout

```
extensions/
  build.sh              assemble dist/ folders and zips
  release.sh            build, tag, and publish a GitHub release of those zips
  INSTALL.md            end-user install guide
  PUBLISHING.md         store submission checklist
  src/
    manifest.chrome.json / manifest.firefox.json
    popup.html / popup.css / popup.js
    prefill.js
    icons/icon{16,32,48,128}.png
  store/
    icon-store-128.png  128×128 listing icon (96×96 art + padding)
  dist/                 generated by build.sh (git-ignored)
```

Edit the app itself at the repo root, then re-run `./build.sh`.
