From 436ce719b2b94bdbf28ef32dbd92bd610aa0f277 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 31 Aug 2026 20:32:15 -0700 Subject: [PATCH] fix: Suppress first-run release notes prompt with --yes-always --- cecli/main.py | 5 ++++- tests/basic/test_main.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/cecli/main.py b/cecli/main.py index 262f7ab1646..1acc7dbf065 100644 --- a/cecli/main.py +++ b/cecli/main.py @@ -1441,7 +1441,10 @@ def get_io(pretty): pre_init_io.tool_output() webbrowser.open(urls.release_notes) return await graceful_exit(coder) - elif args.show_release_notes is None and is_first_run: + elif args.show_release_notes is None and is_first_run and not args.yes_always: + # Suppress the first-run release-notes prompt when --yes-always is set, + # so automated/headless runs don't have the browser hijacked by an + # auto-confirmed offer_url. Explicit --show-release-notes still opens. pre_init_io.tool_output() await pre_init_io.offer_url( urls.release_notes, diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index c2d7b30c186..35c5a146d46 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -372,6 +372,38 @@ def test_main_exit_calls_version_check(dummy_io, git_temp_dir, mocker): mock_input_output.assert_called_once() +def test_suppress_release_notes_prompt_with_yes_always(dummy_io, git_temp_dir, mocker): + mock_input_output = mocker.patch("cecli.io.InputOutput") + mock_input_output.return_value.confirm_ask = AsyncMock(return_value=True) + mock_input_output.return_value.offer_url = AsyncMock() + mocker.patch("cecli.main.is_first_run_of_new_version", return_value=True) + + main(["--exit", "--yes-always"], **dummy_io) + mock_input_output.return_value.offer_url.assert_not_called() + + +def test_shows_release_notes_prompt_on_first_run(dummy_io, git_temp_dir, mocker): + mock_input_output = mocker.patch("cecli.io.InputOutput") + mock_input_output.return_value.confirm_ask = AsyncMock(return_value=True) + mock_input_output.return_value.offer_url = AsyncMock() + mocker.patch("cecli.main.is_first_run_of_new_version", return_value=True) + + main(["--exit"], **dummy_io) + mock_input_output.return_value.offer_url.assert_called_once() + + +def test_explicit_show_release_notes_with_yes_always(dummy_io, git_temp_dir, mocker): + mock_input_output = mocker.patch("cecli.io.InputOutput") + mock_input_output.return_value.confirm_ask = AsyncMock(return_value=True) + mock_input_output.return_value.offer_url = AsyncMock() + mocker.patch("cecli.main.is_first_run_of_new_version", return_value=True) + mocker.patch("webbrowser.open") + + main(["--exit", "--yes-always", "--show-release-notes"], **dummy_io) + # The explicit --show-release-notes code path uses webbrowser.open directly, not offer_url + mock_input_output.return_value.offer_url.assert_not_called() + + def test_main_message_adds_to_input_history(dummy_io, mocker): mocker.patch("cecli.coders.base_coder.Coder.run") MockInputOutput = mocker.patch("cecli.io.InputOutput", autospec=True)