"""Resolve myclaude repository and workspace roots.""" import os from pathlib import Path _MAX_WALK_DEPTH = 16 _MAX_SOURCE_DEPTH = 8 def _pyproject_names_myclaude(path: Path) -> bool: try: text = path.read_text(encoding="utf-8", errors="ignore") except OSError: return False return 'name = "myclaude"' in text or "name = 'myclaude'" in text def _walk_up_for_pyproject(start: Path) -> Path | None: p = start.resolve() for _ in range(_MAX_WALK_DEPTH): candidate = p / "pyproject.toml" if candidate.is_file() and _pyproject_names_myclaude(candidate): return p parent = p.parent if parent == p: break p = parent return None def get_myclaude_project_root() -> Path: """ Root of the myclaude repo (contains Makefile + pyproject). Order: MYCLAUDE_PROJECT_ROOT > walk from cwd > package source tree > ~/.myclaude """ env_root = os.environ.get("MYCLAUDE_PROJECT_ROOT") if env_root: return Path(env_root).expanduser().resolve() try: cwd = Path.cwd() except (OSError, PermissionError): cwd = None if cwd is not None: found = _walk_up_for_pyproject(cwd) if found is not None: return found here = Path(__file__).resolve().parent for _ in range(_MAX_SOURCE_DEPTH): pyproject = here / "pyproject.toml" if pyproject.is_file() and _pyproject_names_myclaude(pyproject): return here if here.parent == here: break here = here.parent return Path.home() / ".myclaude" def get_workspace_root() -> Path: """ Root of the myclaude workspace directory. Order: MYCLAUDE_WORKSPACE_ROOT > project_root/workspace/ > ~/workspace Creates the directory if it does not exist. """ env_root = os.environ.get("MYCLAUDE_WORKSPACE_ROOT") if env_root: root = Path(env_root).expanduser().resolve() else: project_root = get_myclaude_project_root() project_workspace = project_root / "workspace" if project_workspace.is_dir(): root = project_workspace else: root = Path.home() / "workspace" root.mkdir(parents=True, exist_ok=True) return root