"""Atomic environment persistence and the one-time WebSocket default migration.""" import os from pathlib import Path import tempfile from dotenv import dotenv_values from filelock import FileLock TRANSPORT_DEFAULT_VERSION_KEY = "ARTEMIS_TRANSPORT_DEFAULT_VERSION" def _lock(path: Path) -> FileLock: path.parent.mkdir(parents=True, exist_ok=True) return FileLock(str(path) + ".artemis.lock", timeout=5) def _write(path: Path, values: dict[str, str]) -> None: original = path.read_text(encoding="utf-8") if path.exists() else "" kept = [ line for line in original.splitlines() if line.strip().removeprefix("export ").split("=", 1)[0].strip() not in values ] for key, value in values.items(): escaped = value.replace("\\", "\\\\").replace("'", "\\'") kept.append(f"{key}='{escaped}'") fd, temp_name = tempfile.mkstemp(prefix=".env-", dir=path.parent) try: with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as stream: stream.write("\n".join(kept) + "\n") stream.flush() os.fsync(stream.fileno()) os.replace(temp_name, path) finally: Path(temp_name).unlink(missing_ok=True) def persist_environment(path: Path, values: dict[str, str]) -> None: with _lock(path): _write(path, values) os.environ.update(values) def _transport_default_is_current(path: Path) -> bool: saved = dotenv_values(path, interpolate=False) if path.exists() else {} try: return int(saved.get(TRANSPORT_DEFAULT_VERSION_KEY) or "0") >= 1 except ValueError: return False def migrate_transport_default(path: Path) -> bool: """Migrate unversioned HTTP preferences once, preserving later opt-outs.""" # Completed migrations need no write access, including read-only deployments. if _transport_default_is_current(path): return False with _lock(path): if _transport_default_is_current(path): return False values = {"OPENAI_TRANSPORT": "websocket", TRANSPORT_DEFAULT_VERSION_KEY: "1"} _write(path, values) os.environ.update(values) return True