diff --git a/hermes_cli/oneshot.py b/hermes_cli/oneshot.py index b79644f67..1dd24951c 100644 --- a/hermes_cli/oneshot.py +++ b/hermes_cli/oneshot.py @@ -191,11 +191,15 @@ def run_oneshot( except Exception: pass - if response: - real_stdout.write(response) - if not response.endswith("\n"): - real_stdout.write("\n") - real_stdout.flush() + if not (response or "").strip(): + sys.stderr.write("hermes -z: no final response was produced; treating the run as failed.\n") + sys.stderr.flush() + return 1 + + real_stdout.write(response) + if not response.endswith("\n"): + real_stdout.write("\n") + real_stdout.flush() return 0 diff --git a/tests/hermes_cli/test_tui_resume_flow.py b/tests/hermes_cli/test_tui_resume_flow.py index bcf552a8f..ef002c9af 100644 --- a/tests/hermes_cli/test_tui_resume_flow.py +++ b/tests/hermes_cli/test_tui_resume_flow.py @@ -638,6 +638,30 @@ def test_oneshot_rejects_invalid_only_toolsets(monkeypatch, capsys): assert "did not contain any valid toolsets" in err +def test_oneshot_fails_closed_on_empty_final_response(monkeypatch, capsys): + _stub_plugin_discovery(monkeypatch) + import hermes_cli.oneshot as oneshot_mod + + monkeypatch.setattr(oneshot_mod, "_run_agent", lambda *_args, **_kwargs: "") + + assert oneshot_mod.run_oneshot("hello") == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "no final response" in captured.err + + +def test_oneshot_prints_nonempty_final_response(monkeypatch, capsys): + _stub_plugin_discovery(monkeypatch) + import hermes_cli.oneshot as oneshot_mod + + monkeypatch.setattr(oneshot_mod, "_run_agent", lambda *_args, **_kwargs: "done") + + assert oneshot_mod.run_oneshot("hello") == 0 + captured = capsys.readouterr() + assert captured.out == "done\n" + assert captured.err == "" + + def test_oneshot_filters_invalid_toolsets_before_redirect(monkeypatch, capsys): _stub_plugin_discovery(monkeypatch) from hermes_cli.oneshot import _validate_explicit_toolsets