4 Commits
Author SHA1 Message Date
Brandon LiandClaude Opus 5 724ba5581c Drop Task Scheduler; autostart without administrator rights
Register-ScheduledTask failed with Access denied (0x80070005). Writing to the
root task folder needs elevation, so the claim that this install needed no
admin was simply wrong. Rather than demand UAC, use two mechanisms that need
no privileges at all:

- a Startup-folder entry (AutoFirmer.cmd) runs start-all.bat at logon
- PM2's own --cron-restart with --no-autorestart drives the 5-minute update
  check, so PM2 owns the schedule it was already going to resurrect anyway

Both still run in the logged-in interactive session, which is the requirement
that ruled out a Windows service in the first place: the clicker sends real
input and needs a desktop.

pm2 save now runs after the updater is registered, so `pm2 resurrect` brings
back all three processes rather than two.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 18:24:47 -05:00
Brandon LiandClaude Opus 5 7e4714c33d Stop PM2's stderr from aborting the autostart installer
`pm2 delete autofirmer` on a machine that has never registered it writes
"[PM2][ERROR] Process or Namespace autofirmer not found" to stderr. PM2 ships a
PowerShell shim, and under $ErrorActionPreference = 'Stop' any native stderr
becomes a terminating NativeCommandError - so the routine "remove it if it is
there" line killed the install before a single task was registered. The 2>$null
at the call site was useless: the error is raised inside pm2.ps1.

Route every pm2 and npm call through helpers that drop to 'Continue' and judge
by $LASTEXITCODE. npm had the same latent problem, since its warnings also go
to stderr.

Also start Next directly instead of via `npm start`. On Windows npm is a .cmd
shim, so PM2 was supervising the shim while the real server ran as its child -
restarts and stops would have missed the process that actually matters.

The file is now pure ASCII. PowerShell 5.1 reads a non-BOM UTF-8 script as
ANSI, so the box-drawing characters in the comments were a latent hazard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 18:21:59 -05:00
Brandon LiandClaude Opus 5 4288d8c298 Auto-start both processes at logon and self-update from master
Instances were started by hand and updated by hand, so they drifted behind
master silently. Now: PM2 supervises the dashboard and the clicker, a logon
task brings them up, and a 5-minute task pulls, rebuilds and restarts when
master moves.

Restarting on every push is only safe because the scheduler now survives it.
It was pure in-memory state (_global.__autoTrader), so any restart silently
stopped automated trading with the dashboard simply showing it as off. It now
mirrors running/action/symbol/stopAfterAll to the settings table, and
resumeSchedulerIfPersisted() picks it back up from the getClients() bootstrap.
No sync-wait was needed there: tick() already skips while a client reports
!syncComplete and while any account holds a position.

A failed build is never deployed — the build runs before anything restarts, so
a broken push leaves the previous build serving.

start-all and update-check both warm the app with a request afterwards. That is
load-bearing: getClients() is lazily bootstrapped, so until something makes an
HTTP request the Tradovate clients, the reporter and the resumed schedule never
start. That was already true of manual restarts.

Logic lives in Node so a macOS or Linux port only needs an equivalent of
install-autostart.ps1. Python deps are hash-guarded, so the common path is one
hash and one import with no network, and failure is non-fatal since only the
clicker needs them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 17:36:25 -05:00
Brandon LiandClaude Opus 5 9bdd20f83a Add Windows setup script for new instances
Standalone batch file: clones (or pulls), installs, builds, seeds the
reporter settings, and writes a start-autofirmer.bat. Prompts for the master
dashboard URL and instance name, defaulting to %COMPUTERNAME%.

Two install hazards it handles:
- better-sqlite3 has no prebuilt binary above Node 22, so install silently
  falls back to node-gyp and dies without Visual Studio Build Tools. The
  script warns first and names the fix if install fails anyway
- playwright is declared but referenced nowhere in the source, so its
  postinstall browser download is skipped

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 16:16:06 -05:00