"""Shared configuration loader — reads build config from pyproject.toml.""" import re from pathlib import Path from typing import NamedTuple import tomllib class BuildConfig(NamedTuple): """Build configuration extracted from pyproject.toml.""" alfred_version: str python_version: str python_version_short: str image_name: str service_name: str librechat_version: str rag_version: str uv_version: str def extract_python_version(version_string: str) -> tuple[str, str]: """ Extract Python version from uv dependency string. Examples: "==3.14.2" -> ("3.14.2", "3.14") "^3.14.2" -> ("3.14.2", "3.14") """ clean = re.sub(r"^[=^~><]+", "", version_string.strip()) parts = clean.split(".") if len(parts) >= 2: return clean, f"{parts[0]}.{parts[1]}" raise ValueError(f"Invalid Python version format: {version_string}") def load_build_config(base_dir: Path | None = None) -> BuildConfig: """Load build configuration from pyproject.toml.""" if base_dir is None: base_dir = Path(__file__).resolve().parent.parent toml_path = base_dir / "pyproject.toml" if not toml_path.exists(): raise FileNotFoundError(f"pyproject.toml not found: {toml_path}") with open(toml_path, "rb") as f: data = tomllib.load(f) project = data["project"] alfred = data["tool"]["alfred"] python_full, python_short = extract_python_version(project["requires-python"]) return BuildConfig( alfred_version=project["version"], python_version=python_full, python_version_short=python_short, image_name=alfred["image_name"], service_name=alfred["service_name"], librechat_version=alfred["librechat_version"], rag_version=alfred["rag_version"], uv_version=alfred["uv_version"], ) def write_env_make(config: BuildConfig, base_dir: Path | None = None) -> None: """Write .env.make file for Makefile.""" if base_dir is None: base_dir = Path(__file__).resolve().parent.parent lines = [ "# Auto-generated from pyproject.toml — do not edit manually", f"export ALFRED_VERSION={config.alfred_version}", f"export PYTHON_VERSION={config.python_version}", f"export PYTHON_VERSION_SHORT={config.python_version_short}", f"export IMAGE_NAME={config.image_name}", f"export SERVICE_NAME={config.service_name}", f"export LIBRECHAT_VERSION={config.librechat_version}", f"export RAG_VERSION={config.rag_version}", f"export UV_VERSION={config.uv_version}", ] env_make_path = base_dir / ".env.make" env_make_path.write_text("\n".join(lines) + "\n")