From c4b9f14b906b19bc961bd6b6730c7328fa3d0e9e Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Tue, 24 Jun 2025 20:46:40 +0200 Subject: [PATCH] fix: Resolve literal paths correctly in /read-only command --- aider/commands.py | 21 ++++++++++++++++----- tests/basic/test_commands.py | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/aider/commands.py b/aider/commands.py index e21f29d98..9bac9bab1 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1316,12 +1316,23 @@ class Commands: # First collect all expanded paths for pattern in filenames: expanded_pattern = expanduser(pattern) - if os.path.isabs(expanded_pattern): - # For absolute paths, glob it - matches = list(glob.glob(expanded_pattern)) + path_obj = Path(expanded_pattern) + is_abs = path_obj.is_absolute() + if not is_abs: + path_obj = Path(self.coder.root) / path_obj + + matches = [] + # Check for literal path existence first + if path_obj.exists(): + matches = [path_obj] else: - # For relative paths and globs, use glob from the root directory - matches = list(Path(self.coder.root).glob(expanded_pattern)) + # If literal path doesn't exist, try globbing + if is_abs: + # For absolute paths, glob it + matches = [Path(p) for p in glob.glob(expanded_pattern)] + else: + # For relative paths and globs, use glob from the root directory + matches = list(Path(self.coder.root).glob(expanded_pattern)) if not matches: self.io.tool_error(f"No matches found for: {pattern}") diff --git a/tests/basic/test_commands.py b/tests/basic/test_commands.py index d187ee521..47b8832dc 100644 --- a/tests/basic/test_commands.py +++ b/tests/basic/test_commands.py @@ -1621,6 +1621,33 @@ class TestCommands(TestCase): # Clean up: remove the test file from the home directory test_file.unlink() + # pytest tests/basic/test_commands.py -k test_cmd_read_only_with_square_brackets + def test_cmd_read_only_with_square_brackets(self): + with GitTemporaryDirectory() as repo_dir: + io = InputOutput(pretty=False, fancy_input=False, yes=False) + coder = Coder.create(self.GPT35, None, io) + commands = Commands(io, coder) + + # Create test layout + test_dir = Path(repo_dir) / "[id]" + test_dir.mkdir() + test_file = Path(repo_dir) / "[id]" / "page.tsx" + test_file.write_text("Test file") + + # Test the /read-only command + commands.cmd_read_only("[id]/page.tsx") + + # Check if test file was added to abs_read_only_fnames + self.assertTrue( + any(os.path.samefile(str(test_file), fname) for fname in coder.abs_read_only_fnames) + ) + + # Test dropping all read-only files + commands.cmd_drop("[id]/page.tsx") + + # Check if all files were removed from abs_read_only_fnames + self.assertEqual(len(coder.abs_read_only_fnames), 0) + def test_cmd_diff(self): with GitTemporaryDirectory() as repo_dir: repo = git.Repo(repo_dir)