"""Gravity Control — Antigravity Discord Bridge. Entry point that runs the brain watcher and Discord bot together. """ import asyncio import logging import signal import sys from config import Config from watcher import BrainWatcher from bot import GravityBot # Logging setup logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S", handlers=[ logging.StreamHandler(sys.stdout), logging.FileHandler("gravity_control.log", encoding="utf-8"), ], ) logger = logging.getLogger("gravity_control") async def main(): """Run the bridge: watcher + Discord bot.""" # Validate config errors = Config.validate() if errors: for e in errors: logger.error(f"Config error: {e}") logger.error("Fix configuration issues and restart.") sys.exit(1) logger.info("=" * 50) logger.info("Gravity Control — Antigravity Discord Bridge") logger.info("=" * 50) logger.info(f"Brain path: {Config.BRAIN_PATH}") logger.info(f"Debounce: {Config.DEBOUNCE_SECONDS}s") # Shared event queue event_queue = asyncio.Queue() # Get the running loop loop = asyncio.get_running_loop() # Create components watcher = BrainWatcher(event_queue, loop) bot = GravityBot(event_queue) try: # Start watcher (runs in a separate thread via watchdog) watcher.start() logger.info(f"Watcher started, {len(watcher.known_sessions)} existing sessions") # Run Discord bot (blocks until bot disconnects) await bot.start(Config.DISCORD_TOKEN) except KeyboardInterrupt: logger.info("Received keyboard interrupt") except Exception as e: logger.error(f"Fatal error: {e}", exc_info=True) finally: # Cleanup watcher.stop() if not bot.is_closed(): await bot.close() logger.info("Gravity Control shutdown complete") if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: pass