diff --git a/tests/cli/test_cli_resume_command.py b/tests/cli/test_cli_resume_command.py index 299d5fad273c..de2c0fe639be 100644 --- a/tests/cli/test_cli_resume_command.py +++ b/tests/cli/test_cli_resume_command.py @@ -1,3 +1,4 @@ +import os from types import SimpleNamespace from unittest.mock import MagicMock, patch @@ -153,6 +154,78 @@ class TestCliResumeCommand: assert "``, which delegates here) left + the process + ``TERMINAL_CWD`` pointing at whatever directory the user had + cd'd into — so the terminal/code-exec tools and relative paths ran in the + wrong repo. + """ + + def _resumable_cli(self, session_meta): + cli_obj = _make_cli() + cli_obj._session_db.get_session.return_value = session_meta + cli_obj._session_db.get_messages_as_conversation.return_value = [ + {"role": "user", "content": "hello"}, + ] + cli_obj._session_db.resolve_resume_session_id.return_value = session_meta["id"] + return cli_obj + + def test_handle_resume_restores_recorded_cwd(self, tmp_path): + recorded = str(tmp_path) + cli_obj = self._resumable_cli({"id": "sess_dir", "title": "Dir", "cwd": recorded}) + + with ( + patch("hermes_cli.main._resolve_session_by_name_or_id", return_value="sess_dir"), + patch("cli._cprint"), + patch.object(cli_obj, "_console_print"), + patch("os.chdir") as mock_chdir, + patch.dict(os.environ, {}, clear=False), + ): + cli_obj._handle_resume_command("/resume Dir") + # Assert inside the patch.dict scope — it restores os.environ on exit. + assert os.environ.get("TERMINAL_CWD") == recorded + + mock_chdir.assert_called_once_with(recorded) + + def test_handle_resume_without_recorded_cwd_does_not_chdir(self): + # Gateway/remote/older sessions record no cwd — restore must no-op. + cli_obj = self._resumable_cli({"id": "sess_dir", "title": "Dir"}) + + with ( + patch("hermes_cli.main._resolve_session_by_name_or_id", return_value="sess_dir"), + patch("cli._cprint"), + patch.object(cli_obj, "_console_print"), + patch("os.chdir") as mock_chdir, + ): + cli_obj._handle_resume_command("/resume Dir") + + mock_chdir.assert_not_called() + + def test_sessions_command_restores_recorded_cwd(self, tmp_path): + # /sessions delegates to the resume flow, so it restores cwd too. + recorded = str(tmp_path) + cli_obj = self._resumable_cli({"id": "sess_dir", "title": "Dir", "cwd": recorded}) + + with ( + patch("hermes_cli.main._resolve_session_by_name_or_id", return_value="sess_dir"), + patch("cli._cprint"), + patch.object(cli_obj, "_console_print"), + patch("os.chdir") as mock_chdir, + patch.dict(os.environ, {}, clear=False), + ): + cli_obj._handle_sessions_command("/sessions Dir") + # Assert inside the patch.dict scope — it restores os.environ on exit. + assert os.environ.get("TERMINAL_CWD") == recorded + + mock_chdir.assert_called_once_with(recorded) + + class TestPendingResumeNumberedSelection: """Bare `/resume` arms a one-shot prompt so the next bare number resumes.