diff --git a/medeia_macina/cli_entry.py b/medeia_macina/cli_entry.py index e34ea03..8dce23d 100644 --- a/medeia_macina/cli_entry.py +++ b/medeia_macina/cli_entry.py @@ -12,6 +12,34 @@ from pathlib import Path import shlex +def _ensure_repo_root_on_sys_path(pkg_file: Optional[Path] = None) -> None: + """Ensure the repository root (where top-level modules live) is importable. + + The project currently keeps key modules like `CLI.py` at the repo root. + When `mm` is invoked from a different working directory, that repo root is + not necessarily on `sys.path`, which breaks `import CLI`. + + We infer the repo root by walking up from this package location and looking + for a sibling `CLI.py`. + + `pkg_file` exists for unit tests; production uses this module's `__file__`. + """ + try: + pkg_dir = (pkg_file or Path(__file__)).resolve().parent + except Exception: + return + + for parent in pkg_dir.parents: + try: + if (parent / "CLI.py").exists(): + parent_str = str(parent) + if parent_str not in sys.path: + sys.path.insert(0, parent_str) + return + except Exception: + continue + + def _parse_mode_and_strip_args(args: List[str]) -> Tuple[Optional[str], List[str]]: """Parse --gui/--cli/--mode flags and return (mode, cleaned_args). @@ -103,6 +131,7 @@ def _import_medeia_entry_module(): the repository (searching for .egg-link, walking parents, or checking CWD). """ try: + _ensure_repo_root_on_sys_path() return importlib.import_module("medeia_entry") except ImportError: # Try to find the project root next to this installed package @@ -165,6 +194,7 @@ def _run_cli(clean_args: List[str]) -> int: else: # Try importing the top-level `CLI` module directly (editable/repo mode). try: + _ensure_repo_root_on_sys_path() from CLI import MedeiaCLI as _M # type: ignore MedeiaCLI = _M except Exception: diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 0c6030e..b470a6a 100644 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -553,11 +553,16 @@ VENV="$REPO/.venv" # Ensure tools installed into the venv are discoverable to subprocess-based providers export PATH="$VENV/bin:$PATH" +# Ensure top-level repo modules (e.g. CLI.py) are importable even when 'mm' is +# invoked from outside the repo directory. +export PYTHONPATH="$REPO${PYTHONPATH+:$PYTHONPATH}" + # Debug mode: set MM_DEBUG=1 to print repository, venv, and import diagnostics if [ -n "${MM_DEBUG:-}" ]; then echo "MM_DEBUG: diagnostics" >&2 echo "Resolved REPO: $REPO" >&2 echo "Resolved VENV: $VENV" >&2 + echo "PYTHONPATH: ${PYTHONPATH:-}" >&2 echo "VENV exists: $( [ -d "$VENV" ] && echo yes || echo no )" >&2 echo "Candidates:" >&2 echo " VENV/bin/mm: $( [ -x "$VENV/bin/mm" ] && echo yes || echo no )" >&2