"""Configuration module — loads settings from .env file or environment variables.""" import os from pathlib import Path from dotenv import load_dotenv # Load .env from project root load_dotenv(Path(__file__).parent / ".env") class Config: """Bridge configuration.""" # Discord DISCORD_TOKEN: str = os.getenv("DISCORD_TOKEN", "") DISCORD_GUILD_ID: int = int(os.getenv("DISCORD_GUILD_ID") or "0") # Antigravity Brain path # NOTE: os.getenv returns "" (not None) when .env has BRAIN_PATH= (empty value). # Path("") resolves to "." (CWD), which is WRONG. Use `or` to handle both None and "". BRAIN_PATH: Path = Path( os.getenv("BRAIN_PATH") or os.path.expanduser("~/.gemini/antigravity/brain") ) # Watcher settings DEBOUNCE_SECONDS: float = float(os.getenv("DEBOUNCE_SECONDS", "5")) # Files to monitor within each conversation directory (PRIMARY ONLY) WATCHED_FILES: set = { "task.md", "implementation_plan.md", "walkthrough.md", } # Discord message limits DISCORD_MSG_LIMIT: int = 2000 DISCORD_EMBED_DESC_LIMIT: int = 4096 # Channel naming CHANNEL_PREFIX: str = "AG" PROJECT_NAME: str = os.getenv("PROJECT_NAME", "gravity_control") # Bot mode: 'local' (file-based bridge) or 'remote' (HTTP polling — future) BOT_MODE: str = os.getenv("BOT_MODE", "local") REMOTE_BRIDGE_URL: str = os.getenv("REMOTE_BRIDGE_URL", "") @classmethod def validate(cls) -> list[str]: """Return list of configuration errors.""" errors = [] if not cls.DISCORD_TOKEN: errors.append("DISCORD_TOKEN is not set") if not cls.DISCORD_GUILD_ID: errors.append("DISCORD_GUILD_ID is not set") # Gateway mode doesn't need local BRAIN_PATH if cls.BOT_MODE != 'gateway' and not cls.BRAIN_PATH.exists(): errors.append(f"BRAIN_PATH does not exist: {cls.BRAIN_PATH}") return errors