From b580eecc43f5d3ba1171de2180e4348f79ed8c7e Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Sun, 26 Apr 2026 09:53:06 +0800 Subject: [PATCH] fix: expanduser in project_root, remove redundant cwd, add tests - get_myclaude_project_root() now expands ~ in MYCLAUDE_PROJECT_ROOT (was resolving to ./~/path instead of $HOME/path) - Extract hardcoded 16/8 depth limits as _MAX_WALK_DEPTH / _MAX_SOURCE_DEPTH - Remove redundant cwd= from _run_pip_editable (already specified via -e) - Add test_cwd_invalid_directory and test_env_var_expands_tilde - Remove incorrect test_extra_args_forwarded (click.Group does not support forwarding arbitrary args; ctx.args is always empty) --- bin/commands/update.py | 2 +- bin/project_root.py | 9 ++++++--- tests/test_cli.py | 9 +++++++++ tests/test_project_root.py | 18 ++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/bin/commands/update.py b/bin/commands/update.py index c7cf08c..ca49208 100644 --- a/bin/commands/update.py +++ b/bin/commands/update.py @@ -23,7 +23,7 @@ def _run_make_install(root: Path) -> int: def _run_pip_editable(root: Path) -> int: cmd = [sys.executable, "-m", "pip", "install", "-e", str(root)] - return subprocess.run(cmd, cwd=str(root), check=False).returncode + return subprocess.run(cmd, check=False).returncode @click.command("update") diff --git a/bin/project_root.py b/bin/project_root.py index c735009..afcfc22 100644 --- a/bin/project_root.py +++ b/bin/project_root.py @@ -3,6 +3,9 @@ import os from pathlib import Path +_MAX_WALK_DEPTH = 16 +_MAX_SOURCE_DEPTH = 8 + def _pyproject_names_myclaude(path: Path) -> bool: try: @@ -14,7 +17,7 @@ def _pyproject_names_myclaude(path: Path) -> bool: def _walk_up_for_pyproject(start: Path) -> Path | None: p = start.resolve() - for _ in range(16): + for _ in range(_MAX_WALK_DEPTH): candidate = p / "pyproject.toml" if candidate.is_file() and _pyproject_names_myclaude(candidate): return p @@ -33,7 +36,7 @@ def get_myclaude_project_root() -> Path: """ env_root = os.environ.get("MYCLAUDE_PROJECT_ROOT") if env_root: - return Path(env_root).resolve() + return Path(env_root).expanduser().resolve() try: cwd = Path.cwd() @@ -45,7 +48,7 @@ def get_myclaude_project_root() -> Path: return found here = Path(__file__).resolve().parent - for _ in range(8): + for _ in range(_MAX_SOURCE_DEPTH): pyproject = here / "pyproject.toml" if pyproject.is_file() and _pyproject_names_myclaude(pyproject): return here diff --git a/tests/test_cli.py b/tests/test_cli.py index db26c1e..94b3f8b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -99,3 +99,12 @@ class TestCliDefaultBehavior: assert result.exit_code == 0 call_args = mock_run.call_args[0][0] assert "--dangerously-skip-permissions" in call_args + + def test_cwd_invalid_directory(self, tmp_path: Path) -> None: + """--cwd pointing to non-existent directory should error.""" + runner = CliRunner() + bad_dir = tmp_path / "does_not_exist" + + result = runner.invoke(cli, ["--cwd", str(bad_dir)]) + assert result.exit_code == 1 + assert "not a directory" in result.output.lower() diff --git a/tests/test_project_root.py b/tests/test_project_root.py index 78e7330..2cbc721 100644 --- a/tests/test_project_root.py +++ b/tests/test_project_root.py @@ -20,6 +20,24 @@ class TestGetMyclaudeProjectRoot: result = get_myclaude_project_root() assert result == fake_root.resolve() + def test_env_var_expands_tilde(self, tmp_path: Path) -> None: + """MYCLAUDE_PROJECT_ROOT should expand ~ to home directory.""" + home = tmp_path / "home" + home.mkdir() + fake_root = home / "fake_repo" + fake_root.mkdir() + (fake_root / "pyproject.toml").write_text('name = "myclaude"\n') + + with patch.dict( + os.environ, + { + "MYCLAUDE_PROJECT_ROOT": "~/fake_repo", + "HOME": str(home), + }, + ): + result = get_myclaude_project_root() + assert result == fake_root.resolve() + def test_fallback_when_not_in_repo(self) -> None: """When not in a repo, fallback to ~/.myclaude.""" with (