From dec3b03d53eca0d2f8c018bcf8dc2771c5fa4f28 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Thu, 16 Apr 2026 07:24:52 +0000 Subject: [PATCH] feat(run): auto-focus TradeStation by window_title at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pygetwindow.activate() brings the calibrated window to the foreground so the user doesn't need to alt-tab during the startup-delay. Largest window matching cfg.window_title (case-insensitive substring) wins. If minimized, restore first. Failures are warnings, not errors — user can still focus it manually during the countdown. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/atm/main.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/atm/main.py b/src/atm/main.py index 11e2ca6..b2cb61d 100644 --- a/src/atm/main.py +++ b/src/atm/main.py @@ -177,9 +177,31 @@ def _cmd_run(args) -> None: duration_s = (stop - now).total_seconds() print(f"Will stop at {stop:%Y-%m-%d %H:%M} (duration {duration_s/3600:.2f}h)", flush=True) + # Auto-focus TradeStation by title substring so user doesn't need to alt-tab + if not capture_stub and cfg.window_title: + try: + import pygetwindow as gw # type: ignore[import-untyped] + needle = cfg.window_title.lower() + matches = [w for w in gw.getAllWindows() if w.title and needle in w.title.lower()] + # Prefer largest window (the main chart, not a tooltip or child) + matches.sort(key=lambda w: (w.width or 0) * (w.height or 0), reverse=True) + if matches: + win = matches[0] + try: + if win.isMinimized: + win.restore() + win.activate() + print(f"Focused window: {win.title!r}", flush=True) + except Exception as exc: + print(f"Could not focus {win.title!r}: {exc}", flush=True) + else: + print(f"WARN: no window contains {cfg.window_title!r} — bring TradeStation to front manually", flush=True) + except ImportError: + pass + delay = getattr(args, "startup_delay", 0.0) if delay > 0 and not capture_stub: - print(f"Bring TradeStation to front, minimize PowerShell/VS Code. Starting in {delay:.0f}s...", flush=True) + print(f"Starting in {delay:.0f}s (TradeStation should be in front)...", flush=True) for i in range(int(delay), 0, -1): print(f" {i}...", flush=True) time.sleep(1.0)