Files
autofirmer-expanded/extension
Brandon LiandClaude Opus 5 b748f95372 Add automation framework, typing, and runner for the autobuyer
Turns the autobuyer from a page scraper into something that acts. A dashboard
button queues a run; a desktop process executes it against the real browser.

lib/automations.ts — automations are declarative step lists nested inside the
firm whose site they drive. Steps are click / type / wait / navigate, and they
inherit the firm's tab pattern and URL, so one firm's automation can't act on
another's tab. Adding a button means adding an entry here; the page renders
buttons from the API and the runner receives steps from the server, so neither
needs editing. Runs key on firm:automation — every firm will plausibly have its
own "buy-accounts", and a bare id would resolve to the wrong one.

clicker/runner.py — the daemon behind the buttons. Claims a queued run, works
through the steps, reports each one back for the page's live log. Only one run
executes at a time: two processes driving one physical mouse would interleave
clicks. Heartbeats on its own thread, because a step can block for tens of
seconds and folding the beat into the main loop would show the runner as offline
in the middle of the run it was executing.

clicker/actions.py — one implementation of the safety checks, shared by the CLI
and the runner. Refuses to act when the element is covered by an overlay, when
coordinates fall off-screen, when the browser can't be confirmed frontmost, or
(for type) when the target isn't an editable field.

Typing: uneven human cadence, and the field is read back afterwards and compared
against what was typed — a field that never took focus fails silently and looks
identical to success otherwise. Non-ASCII is rejected because pyautogui skips
those characters without complaint, and newlines because Enter may submit the
form. Typos are deliberately not simulated: a mistyped digit in a trading form
is a real loss, and the correction is the part that can go wrong.

Extension: opens the firm's page when no tab matches, navigates to a specific
page for a navigate step (skipped when already there, so page state survives),
and retries the locate while a freshly loaded React app mounts — `complete` only
means the document loaded.

Staleness reporting, after it cost three debugging rounds: Chrome doesn't reload
an unpacked extension and Python doesn't reload a running process, so both now
report their version. A stale runner gets a red banner naming both versions and
the automation buttons are disabled, rather than failing mid-run on a step type
it predates.

Scale detection is now conservative: a raw OS/browser width ratio is only
trusted when it lands on a real scaling factor. On this multi-monitor desktop
the previous logic would have silently halved every coordinate.

Verified end to end against the live browser: navigate, locate, and a real
click (run #12, all three steps). API round-trips, claim-once semantics, run
cancellation, the heartbeat online/offline lifecycle, motion geometry and
timing, focus activation, and typing verification all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 14:00:33 -05:00
..

AutoFirmer Capture (Chromium extension)

Polls the dashboard for an on/off flag and, while it's on, scrapes the target tab's HTML and posts it back to the dashboard.

Install (unpacked)

  1. Start the dashboard (npm run dev) so http://localhost:3000 is up.
  2. Open chrome://extensions, enable Developer mode (top right).
  3. Load unpacked → select this extension/ folder.
  4. Click the extension icon to open the popup and set:
    • Dashboard URL — default http://localhost:3000. Use the VPS IP if the dashboard runs elsewhere.
    • Poll interval — seconds between status checks (default 3).
    • Target URL pattern — a Chrome match pattern like https://*.tradovate.com/*. Leave blank to capture whichever tab is active.
    • Element selector — optional CSS selector; matching elements get their on-screen position measured alongside the HTML.

The badge shows ON (green) while capturing, ! (red) if the dashboard is unreachable, and nothing when the switch is off.

Flow

AutoBuyer page  --PATCH /api/autobuyer/status-->  SQLite settings
extension       --GET   /api/autobuyer/status-->  { enabled }
extension       --POST  /api/autobuyer/capture->  html + viewport + element rects
AutoBuyer page  --GET   /api/autobuyer/capture->  renders the HTML

Scope

host_permissions is deliberately narrow — https://*.tradeify.co/* plus localhost for the dashboard. The extension is technically incapable of reading any other site, so an accidental capture of your bank or mail tab can't happen. The default Target URL pattern matches, so it only ever captures the broker tab regardless of which tab is focused.

To automate a different broker, add its pattern to host_permissions in manifest.json, update the popup's target pattern, and reload the extension. Avoid going back to <all_urls> — that re-enables scraping whatever tab is active.

Notes

  • The extension never captures the dashboard's own pages — otherwise it would just mirror its own output back.
  • chrome://, about: and Web Store pages cannot be scripted by any extension; they're skipped.
  • MV3 service workers are torn down when idle. Each poll makes an extension API call, which keeps the worker alive; a 30-second alarm revives it if Chrome kills it anyway. So worst-case cadence is 30s, normal cadence is the poll interval.