diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 53cef76771..aad45eb2e3 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1278,6 +1278,14 @@ def _launch_tui( if "--expose-gc" not in _tokens: _tokens.append("--expose-gc") env["NODE_OPTIONS"] = " ".join(_tokens) + # HERMES_TUI_RESUME is an internal hand-off from the Python wrapper to the + # Ink app. Because we start from os.environ.copy(), an exported/stale value + # in the user's shell would otherwise make a plain `hermes --tui` try to + # resume a non-existent session and leave the UI at "error: session not + # found" with no live session. Only forward a resume id that argparse + # resolved for this invocation; direct `node ui-tui/dist/entry.js` users can + # still set HERMES_TUI_RESUME themselves. + env.pop("HERMES_TUI_RESUME", None) if resume_session_id: env["HERMES_TUI_RESUME"] = resume_session_id diff --git a/tests/hermes_cli/test_tui_resume_flow.py b/tests/hermes_cli/test_tui_resume_flow.py index bfdea103ae..0c3cde535c 100644 --- a/tests/hermes_cli/test_tui_resume_flow.py +++ b/tests/hermes_cli/test_tui_resume_flow.py @@ -541,6 +541,48 @@ def test_launch_tui_exit_code_42_relaunches_update(monkeypatch, main_mod): mock_relaunch.assert_called_once_with(["update"], preserve_inherited=False) +def test_launch_tui_drops_stale_resume_env_without_resume_arg(monkeypatch, main_mod): + captured = {} + + monkeypatch.setenv("HERMES_TUI_RESUME", "stale-missing-session") + monkeypatch.setattr( + main_mod, + "_make_tui_argv", + lambda tui_dir, tui_dev: (["node", "dist/entry.js"], Path(".")), + ) + monkeypatch.setattr( + main_mod.subprocess, + "call", + lambda argv, cwd=None, env=None: captured.update({"env": env}) or 1, + ) + + with pytest.raises(SystemExit): + main_mod._launch_tui() + + assert "HERMES_TUI_RESUME" not in captured["env"] + + +def test_launch_tui_sets_resume_env_from_resume_arg(monkeypatch, main_mod): + captured = {} + + monkeypatch.setenv("HERMES_TUI_RESUME", "stale-missing-session") + monkeypatch.setattr( + main_mod, + "_make_tui_argv", + lambda tui_dir, tui_dev: (["node", "dist/entry.js"], Path(".")), + ) + monkeypatch.setattr( + main_mod.subprocess, + "call", + lambda argv, cwd=None, env=None: captured.update({"env": env}) or 1, + ) + + with pytest.raises(SystemExit): + main_mod._launch_tui(resume_session_id="20260518_000000_goodid") + + assert captured["env"]["HERMES_TUI_RESUME"] == "20260518_000000_goodid" + + def test_make_tui_argv_dev_prebuilds_hermes_ink(monkeypatch, main_mod, tmp_path): tui_dir = tmp_path / "ui-tui" tsx = tui_dir / "node_modules" / ".bin" / "tsx"