"""Shared argument parsing for ollie tool scripts. Tools receive a JSON object on stdin. This module reads and parses it, providing a simple interface for extracting required and optional fields. Usage: from _lib.args import parse_args args = parse_args() path = args.require("path") start = args.get("start") # None if missing """ import json import sys class Args: """Parsed tool arguments from stdin JSON.""" def __init__(self, data: dict): self._data = data def require(self, key: str) -> str: """Get a required argument. Exits with error if missing.""" if key not in self._data or self._data[key] is None: print(f"error: missing required argument: {key}", file=sys.stderr) sys.exit(1) return str(self._data[key]) def get(self, key: str, default=None): """Get an optional argument.""" v = self._data.get(key) if v is None: return default return str(v) if isinstance(v, (str, int, float, bool)) else v def get_list(self, key: str) -> list: """Get an argument expected to be a list.""" v = self._data.get(key) if v is None: return [] if isinstance(v, list): return v return [v] def get_bool(self, key: str, default=False) -> bool: """Get a boolean argument.""" v = self._data.get(key) if v is None: return default if isinstance(v, bool): return v return str(v).lower() in ("true", "1", "yes") def get_int(self, key: str, default=None): """Get an integer argument.""" v = self._data.get(key) if v is None: return default return int(v) def raw(self) -> dict: """Return the raw parsed dict.""" return self._data def parse_args() -> Args: """Read JSON args from stdin and return an Args instance.""" try: data = json.load(sys.stdin) except (json.JSONDecodeError, ValueError): data = {} if not isinstance(data, dict): data = {} return Args(data)