Let the extension update itself, and host the dashboard

Chrome has no update channel for an unpacked extension, so every pull left one
manual step: click reload on its card. The dashboard now publishes the version
its own checkout ships at /api/autobuyer/status, and the extension reloads
itself when it is behind — chrome.runtime.reload() re-reads the folder from
disk, which the update check has already pulled into. It only ever runs code
that is on disk, so a reload that changes nothing is reported and waited out
rather than repeated; a dashboard that is behind is ignored.

Also adds the deploy stack for running the dashboard on the droplet, next to
the autotrader one: it joins that nginx's network and renders a server block
into its conf.d rather than standing up a second ingress. AUTOFIRMER_DB moves
the SQLite file onto a volume, since the working directory in a container is
replaced on every deploy.

And waitFor gained `hidden`: an absent gate matched on DOM presence only, so a
modal that closes by going display:none could never satisfy it. The extension
grew a visibility probe for this — locate cannot answer it, because absent and
hidden are both errors there and a wait gate has to tell them apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-08-31 12:30:59 -05:00
co-authored by Claude Opus 5
parent 1f4459985a
commit d1e8668440
18 changed files with 637 additions and 28 deletions
+34 -5
View File
@@ -131,9 +131,11 @@ pick it up from the server.
`chrome://extensions` → enable **Developer mode** → **Load unpacked** →
select the `extension` folder.
Chrome does **not** reload an unpacked extension when its files change. After
pulling updates, click the reload icon on its card — the dashboard shows the
version it sees, and a mismatch means the reload did not take.
Chrome does **not** reload an unpacked extension when its files change, and it
has no update channel for one either. The extension therefore checks the version
the dashboard ships on every poll and reloads *itself* when it is behind, which
re-reads the folder from disk. Clicking the reload icon on its card still works
and is the thing to try when something looks stuck.
Adding a new firm also means adding its host to `host_permissions` in
`extension/manifest.json` and reloading. Without it the extension cannot read
@@ -280,6 +282,25 @@ New-NetFirewallRule -DisplayName "AutoFirmer" -Direction Inbound -Protocol TCP -
---
## Hosting the dashboard on a server
The dashboard can run on the droplet instead of on the trading machine, with the
clicker and the extension pointing at it over HTTPS. The clicker and the
extension cannot move — one needs a desktop to send real input to, the other is
your browser.
```bash
cp deploy/.env.example deploy/.env # set FIRMER_HOST
./deploy/bootstrap-tls.sh # first run: certificate, then deploy
./deploy/deploy.sh # every run after that
```
It shares the droplet's existing nginx and certbot rather than standing up its
own, and the database lives on a Docker volume. There is no login on it. See
[deploy/README.md](deploy/README.md) before opening it to the internet.
---
## Updating
Once auto-start is installed, nothing here is manual. Every 5 minutes the update
@@ -318,11 +339,19 @@ To apply an update immediately rather than waiting for the next check:
node scripts\update-check.mjs
```
### The two things that still do not reload themselves
### What reloads itself, and what does not
- **The extension** — click reload on its card in `chrome://extensions`.
- **The extension** reloads itself now. `/api/autobuyer/status` reports the
version the dashboard's own checkout ships; when the running build is older,
the extension calls `chrome.runtime.reload()` and comes back on the files the
update check pulled. It only ever runs code already on disk, so if it reloads
before the pull lands it says so in the popup and waits rather than restarting
in a loop. Clicking reload on its card is still the manual fallback.
- **The scheduler is fine now.** It persists to the settings table and resumes
after a restart, so an update no longer silently stops automated trading.
- **The runner** does not. It is a long-lived Python process; the update check
restarts it when anything under `clicker/` changes, and the dashboard warns
when the version it reports is behind what the server expects.
The dashboard reports the version it sees from the extension and the runner, and
warns when either is behind. Most AutoBuyer bugs that look mysterious are the