diff --git a/src/codexchange/config.py b/src/codexchange/config.py new file mode 100644 index 0000000..0f7c703 --- /dev/null +++ b/src/codexchange/config.py @@ -0,0 +1,97 @@ +"""Configuration management for CodeXchange CLI.""" + +import os +from pathlib import Path +from typing import Optional + +import yaml +from pydantic import BaseModel + + +class ConfigSettings(BaseModel): + """Configuration settings for CodeXchange CLI.""" + + ollama_host: str = "http://localhost:11434" + default_model: str = "codellama" + timeout: int = 300 + verbose: bool = False + + model_config = { + "populate_by_name": True + } + + +def get_config_path() -> Path: + """Get the path to the configuration file.""" + return Path.home() / ".codexchange.yaml" + + +def load_config(config_path: Optional[Path] = None) -> ConfigSettings: + """Load configuration from file. + + Args: + config_path: Optional path to config file. If not provided, uses default location. + + Returns: + ConfigSettings object with loaded configuration. + """ + if config_path is None: + config_path = get_config_path() + + config = ConfigSettings() + + if config_path.exists(): + try: + with open(config_path, "r") as f: + config_data = yaml.safe_load(f) or {} + config = ConfigSettings(**config_data) + except (yaml.YAMLError, IOError) as e: + print(f"Warning: Failed to load config file: {e}") + + return config + + +def save_config(config: ConfigSettings, config_path: Optional[Path] = None) -> None: + """Save configuration to file. + + Args: + config: ConfigSettings object to save. + config_path: Optional path to config file. If not provided, uses default location. + """ + if config_path is None: + config_path = get_config_path() + + config_dict = config.model_dump(exclude_none=True) + + config_path.parent.mkdir(parents=True, exist_ok=True) + + with open(config_path, "w") as f: + yaml.dump(config_dict, f, default_flow_style=False) + + +def get_config() -> ConfigSettings: + """Get configuration with environment variable overrides. + + Environment variables: + CODEXCHANGE_OLLAMA_HOST: Ollama host URL + CODEXCHANGE_DEFAULT_MODEL: Default model name + CODEXCHANGE_TIMEOUT: Request timeout in seconds + + Returns: + ConfigSettings object with merged configuration. + """ + config = load_config() + + if os.getenv("CODEXCHANGE_OLLAMA_HOST"): + config.ollama_host = os.getenv("CODEXCHANGE_OLLAMA_HOST", "") + + if os.getenv("CODEXCHANGE_DEFAULT_MODEL"): + config.default_model = os.getenv("CODEXCHANGE_DEFAULT_MODEL", "") + + if os.getenv("CODEXCHANGE_TIMEOUT"): + try: + config.timeout = int(os.getenv("CODEXCHANGE_TIMEOUT") or "300") + except ValueError: + pass + + return config