diff --git a/run_catser.py b/run_catser.py new file mode 100644 index 0000000..d7da537 --- /dev/null +++ b/run_catser.py @@ -0,0 +1,119 @@ +""" +Catser Launcher and CLI Interface. + +Usage: + py run_catser.py # Run Catser with default settings + py run_catser.py --test # Test mode: triggers an immediate attack run & paw swipe + py run_catser.py --coat charcoal # Run with Charcoal coat + py run_catser.py --action minimize # Minimize distraction windows instead of closing + py run_catser.py --help # View all options +""" + +import sys +import argparse +import logging +from catser.config import Config, COATS +from catser.app import CatserApp + + +def setup_logging(verbose: bool = False) -> None: + """Configures console logging format.""" + level = logging.DEBUG if verbose else logging.INFO + logging.basicConfig( + level=level, + format="[%(asctime)s] [%(levelname)s] %(name)s: %(message)s", + datefmt="%H:%M:%S", + ) + + +def main() -> None: + """CLI entry point for Catser.""" + parser = argparse.ArgumentParser( + prog="Catser", + description="Desktop Cat Companion that closes Shorts, Reels, and distracting windows via ActivityWatch!", + ) + parser.add_argument( + "--coat", + choices=list(COATS.keys()), + default="ivory", + help="Select cat coat color (default: ivory)", + ) + parser.add_argument( + "--action", + choices=["close", "minimize", "notify"], + default="close", + help="Action to perform when cat hits the window (default: close)", + ) + parser.add_argument( + "--aw-url", + default="http://localhost:5600", + help="ActivityWatch server URL (default: http://localhost:5600)", + ) + parser.add_argument( + "--add-keyword", + action="append", + dest="extra_keywords", + help="Add additional window title keywords to target as distractions", + ) + parser.add_argument( + "--width", + type=int, + default=144, + help="Width of the cat on screen in pixels (default: 144)", + ) + parser.add_argument( + "--test", + action="store_true", + help="Run in test mode: launches Catser, performs a test sprint & paw swipe, and runs for 6 seconds", + ) + parser.add_argument( + "--verbose", "-v", + action="store_true", + help="Enable detailed debug logging", + ) + + args = parser.parse_args() + setup_logging(args.verbose) + + config = Config( + aw_url=args.aw_url, + action_on_hit=args.action, + coat_name=args.coat, + cat_width=args.width, + ) + + if args.extra_keywords: + config.distraction_keywords.extend(args.extra_keywords) + + print("=" * 60) + print(" Catser - Desktop Cat Companion for Windows") + print(f" Coat: {config.coat_name.capitalize()} | Action: {config.action_on_hit.upper()}") + print(f" ActivityWatch: {config.aw_url}") + print(f" Targets: {', '.join(config.distraction_keywords)}") + print("=" * 60) + print(" Controls:") + print(" - Drag cat: Click and drag with mouse (picks up by scruff)") + print(" - Pet cat: Click once without dragging (happy reaction)") + print(" - Exit: Press Ctrl+C in this terminal") + print("=" * 60) + + app = CatserApp(config) + app.initialize() + + if args.test: + print("[TEST MODE] Triggering test attack to top-right screen in 1.5s...") + # Schedule test attack after brief delay + import threading + def _demo(): + import time + time.sleep(1.5) + app.trigger_test_attack() + + threading.Thread(target=_demo, daemon=True).start() + app.run(max_seconds=6.0) + else: + app.run() + + +if __name__ == "__main__": + main()