Files
autofirmer-expanded/extension
Brandon LiandClaude Opus 5 22db6eae8d Add repeat blocks, per-run inputs, skipIfNotFound, and orphaned-run recovery
Repeat. A `repeat` block runs its steps several times, with the count either
fixed in the config or taken from an input the user sets on the dashboard. The
block is unrolled in resolveSteps before the runner sees it, so the runner needs
no loop, the run's total step count stays honest, and every iteration appears in
the log as its own line — a failure on the third purchase reads as "(3/5)"
rather than as an indistinguishable repeat of the first.

Counts are clamped server-side against the automation's declared min/max, and
expansion is capped at 400 steps and three levels of nesting. Each iteration can
be a purchase, so the number is not taken on trust from the client, and the
confirmation dialog names it before anything runs.

skipIfNotFound on a click or type step tolerates an element that is not on the
page — a cookie banner, a modal that only sometimes appears. Only absence is
tolerated. That distinction needed a new NotFoundError: previously a missing
element, an unreachable dashboard, a missing tab and a covered button all
surfaced as the same DashboardError, and skipping that whole class would mean a
step quietly passing while the extension was down.

Orphaned runs are now reaped. Only one run executes at a time, so a run left in
'running' when its runner went away blocked every future run — restarting the
daemon mid-run deadlocked the queue, which is exactly what happened. The
heartbeat decides: a runner that is gone, or up and reporting idle, is not
driving that run whatever the status column says. Gated on the busy flag rather
than elapsed time alone, since a run sitting in a waitFor gate or a sign-in wait
can legitimately go minutes without progress.

Lucid Trading is scaffolded with no automations yet. One match pattern covers
both its hosts — `*.` matches the apex as well as subdomains, confirmed against
a live tab. Its signed-out pattern is `//lucidtrading.com/` rather than
`lucidtrading.com/dashboard`: the leading slashes anchor it to the start of the
host, and without them the substring also matches dash.lucidtrading.com, which
would abort every step while properly signed in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:22:45 -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.