diff --git a/aider/commands.py b/aider/commands.py index aaf6d7ddd..6669f7781 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1437,12 +1437,32 @@ class Commands: self.io.tool_error(f"Error reading file: {e}") return - for cmd in commands: - cmd = cmd.strip() + self._execute_commands(commands) + + def cmd_loadscript(self, args): + "Run a shell script/program and execute each non-empty stdout line as a command." + if not args.strip(): + self.io.tool_error("Please provide a script to run.") + return + + # Run the script, capture its stdout + exit_status, output = run_cmd( + args, + verbose=self.verbose, + error_print=self.io.tool_error, + cwd=(self.coder.root if self.coder else None), + ) + if output is None: + return + + # Split into non-empty lines and execute each as a command + self._execute_commands(output.splitlines()) + + def _execute_commands(self, commands): + for line in commands: + cmd = line.strip() if not cmd or cmd.startswith("#"): continue - - self.io.tool_output(f"\nExecuting: {cmd}") try: self.run(cmd) except SwitchCoder: diff --git a/tests/basic/test_commands.py b/tests/basic/test_commands.py index d187ee521..536199061 100644 --- a/tests/basic/test_commands.py +++ b/tests/basic/test_commands.py @@ -2106,6 +2106,17 @@ class TestCommands(TestCase): "Command '/model gpt-4' is only supported in interactive mode, skipping." ) + def test_loadscript(self): + # Test that /loadscript can run shell that is interpreted as aider commands + # Create some test files + with open("test1.py", "w") as f: + f.write("print('test1')") + io = InputOutput(pretty=False, fancy_input=False, yes=True) + coder = Coder.create(self.GPT35, None, io) + commands = Commands(io, coder) + commands.cmd_loadscript("echo /add test1.py") + self.assertIn(str(Path("test1.py").resolve()), coder.abs_fnames) + def test_reset_after_coder_clone_preserves_original_read_only_files(self): with GitTemporaryDirectory() as _: repo_dir = str(".")