Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mistral-vibe for openSUSE:Factory checked in at 2026-09-09 16:19:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mistral-vibe (Old) and /work/SRC/openSUSE:Factory/.mistral-vibe.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mistral-vibe" Wed Sep 9 16:19:56 2026 rev:17 rq:1376417 version:2.25.0 Changes: -------- --- /work/SRC/openSUSE:Factory/mistral-vibe/mistral-vibe.changes 2026-09-04 12:41:31.791943961 +0200 +++ /work/SRC/openSUSE:Factory/.mistral-vibe.new.1265/mistral-vibe.changes 2026-09-09 16:22:14.740762374 +0200 @@ -1,0 +2,50 @@ +Sun Sep 6 15:49:53 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to 2.25.0: + * Add an experimental /skills browser with search and filter; + shared skills sync on session start + * Add "vibe update" to check for and install a newer release + * Expose plugin-declared MCP servers in /mcp, authenticatable + via /mcp login, and discover Mistral's built-in web-search + connector + * Add connectors (Notion, Linear, Slack, GitHub, Gmail, Google + Calendar, Drive) to ACP + * Run prompt queueing through the app server, with select, + edit, remove, pause and resume controls + * vibe --yolo now selects the auto-approve profile; /config + saves to the user config by default + * Approved file operations act on the cleared path, so a + symlink can no longer redirect a write outside the project + * Fix crashes on a malformed browser_auth_api_base_url port and + on a JSON-Patch move in the session event stream + * Drop Devstral Small from the default models list; stale + sparse config overrides are migrated automatically + * Many more fixes and improvements; see upstream's release + notes for the full list +- Rebase no_network.patch, no_terminal.patch, fix_ui_tests.patch + and warning_cleanup.patch +- Rebase obs-test-synchronization.patch and drop its + test_queue_selection_ui.py hunks: upstream removed the + blocking-bash queue tests they synchronised +- Add missing runtime dependency on python3-setproctitle, which + upstream requires to rename the process to "Vibe CLI" +- Add fingerprint_file_contents.patch: the config file + fingerprint was dev:inode:mtime:size, so rewriting a config + file with different data of the same length inside one + filesystem timestamp tick left it unchanged and the edit went + unnoticed, which lost a concurrent write and kept a stale + config loaded. The contents are now hashed in as well + (submitted upstream) +- Stop exporting PYTHONTRACEMALLOC=20 when running the test + suite: recording a 20-frame traceback for every allocation made + it about 29 times slower (2h25m to 5min) and turned some 44 + timing-sensitive tests into spurious timeout failures +- Cap pytest-xdist at 4 workers: upstream sets "-n auto", so the + suite otherwise differs with the builder's CPU count, and + many-core workers exhaust the pty pool +- Move the test suite into a "test" multibuild flavour, so the + shipped package no longer waits on it and is not blocked by it. + The test flavour carries the test-only BuildRequires, declares + no files and produces only a src.rpm + +------------------------------------------------------------------- Old: ---- mistral-vibe-2.24.5.tar.gz New: ---- _multibuild fingerprint_file_contents.patch mistral-vibe-2.25.0.tar.gz ----------(New B)---------- New: upstream requires to rename the process to "Vibe CLI" - Add fingerprint_file_contents.patch: the config file fingerprint was dev:inode:mtime:size, so rewriting a config ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mistral-vibe.spec ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:15.938812297 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:15.940812380 +0200 @@ -15,8 +15,20 @@ # Please submit bugfixes or comments via https://bugs.opensuse.org/ # -Name: mistral-vibe -Version: 2.24.5 +%global flavor @BUILD_FLAVOR@%{nil} +%if "%{flavor}" == "test" +%define psuffix -test +# the test flavour installs into the buildroot only so that %%check has an +# importable tree on PYTHONPATH; it declares no %%files and ships nothing +%define _unpackaged_files_terminate_build 0 +%bcond_without test +%else +%define psuffix %{nil} +%bcond_with test +%endif +%define origname mistral-vibe +Name: %{origname}%{psuffix} +Version: 2.25.0 Release: 0 Summary: Minimal CLI coding agent by Mistral License: Apache-2.0 @@ -43,6 +55,10 @@ # PATCH-FIX-OPENSUSE obs-test-synchronization.patch [email protected] # make UI tests robust on slow build workers Patch6: obs-test-synchronization.patch +# PATCH-FIX-UPSTREAM fingerprint_file_contents.patch gh#mistralai/mistral-vibe#1064 [email protected] +# a same-length config rewrite inside one filesystem timestamp tick was +# invisible to the file fingerprint; hash the contents too +Patch7: fingerprint_file_contents.patch BuildRequires: fdupes BuildRequires: python-rpm-macros BuildRequires: python3-base >= 3.12 @@ -51,6 +67,8 @@ BuildRequires: python3-hatchling BuildRequires: python3-pip BuildRequires: python3-rfc8785 >= 0.1.4 +BuildArch: noarch +%if !%{with test} Requires: python3-GitPython >= 3.1.57 Requires: python3-PyJWT >= 2.13.0 Requires: python3-PyYAML >= 6.0.3 @@ -124,6 +142,7 @@ Requires: python3-rich >= 15.0.0 Requires: python3-rpds-py >= 0.30.0 Requires: python3-sentry-sdk >= 2.64.0 +Requires: python3-setproctitle >= 1.3.7 Requires: python3-six >= 1.17.0 Requires: python3-smmap >= 5.0.3 Requires: python3-sounddevice >= 0.5.5 @@ -152,8 +171,9 @@ Provides: python313-mistral-vibe = %{version} Provides: python314-mistral-vibe = %{version} Obsoletes: python314-mistral-vibe < %{version} -BuildArch: noarch +%endif # SECTION test requirements +%if %{with test} BuildRequires: ca-certificates BuildRequires: ca-certificates-mozilla BuildRequires: python3-GitPython >= 3.1.57 @@ -257,6 +277,7 @@ BuildRequires: python3-zipp >= 3.23.1 BuildRequires: python3-zstandard >= 0.25.0 BuildRequires: tree-sitter-bash +%endif # /SECTION %description @@ -266,7 +287,7 @@ with your projects through a powerful set of tools. %prep -%autosetup -p1 +%autosetup -p1 -n %{origname}-%{version} %build %python3_pyproject_wheel @@ -275,13 +296,22 @@ %python3_pyproject_install %fdupes %{buildroot}%{python3_sitelib} +%if %{with test} %check -export PYTHONTRACEMALLOC=20 -PYTEST_ADDOPTS="--ignore=tests/audio_player/test_audio_player.py --timeout=60" +# Do NOT set PYTHONTRACEMALLOC here: recording a 20-frame traceback for every +# allocation made the suite about 29 times slower (2h25m -> 5min) and turned +# roughly 44 timing-sensitive tests into spurious timeout failures. +# Upstream's pyproject.toml sets "-n auto", one xdist worker per CPU; cap it so +# the suite is the same everywhere instead of varying with the builder's CPU +# count, and so many-core workers do not exhaust the pty pool. A later -n +# overrides the ini value. +PYTEST_ADDOPTS="--ignore=tests/audio_player/test_audio_player.py --timeout=60 -n 4" export PYTEST_ADDOPTS+=" --ignore=tests/audio_recorder/test_audio_recorder.py" export PYTEST_ADDOPTS+=" --ignore=tests/snapshots" %python3_pytest -m 'not (network or terminal)' -k 'not test_generic_backend_streaming_uses_ssl_cert_file' +%endif +%if !%{with test} %files %license LICENSE %doc README.md @@ -290,4 +320,5 @@ %{_bindir}/vibe-app-server %{python3_sitelib}/vibe %{python3_sitelib}/mistral_vibe-%{version}.dist-info +%endif ++++++ _multibuild ++++++ <multibuild> <flavor>test</flavor> </multibuild> ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.001814922 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.004815047 +0200 @@ -1,5 +1,5 @@ -mtime: 1788328899 -commit: 70cc33cf11450a10c02645526f1a33e70ac551f382496f1923e07e229eb87ff8 +mtime: 1788715116 +commit: c1044986e1fe5d923f2f53f27f3f11e52f0660460b483b82f505a2b9a26b9d6f url: https://src.opensuse.org/AI/mistral-vibe.git revision: factory ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-09-06 19:18:36.000000000 +0200 @@ -0,0 +1,9 @@ +.assets +_build.* +*.obscpio +*.obsinfo +*.osc +.pbuild +_service:* +mistral-vibe-*-build/ +.aider* ++++++ fingerprint_file_contents.patch ++++++ From: Martin Pluskal <[email protected]> Subject: fingerprint: detect same-length rewrites within one timestamp tick create_file_fingerprint() returned dev:ino:mtime_ns:size, so rewriting a config file with different data of the same length inside one filesystem timestamp tick left every component unchanged and the change went unnoticed. st_ctime_ns does not help: it comes from the same clock and does not tick either (measured: 1959 of 2000 same-length rewrites undetectable, 0 of 2000 with contents hashed). Contents are read with os.pread() so the caller's file position is untouched and the O_RDWR temp handle of the atomic-write path can still be fingerprinted. Index: mistral-vibe-2.25.0/vibe/core/config/fingerprint.py =================================================================== --- mistral-vibe-2.25.0.orig/vibe/core/config/fingerprint.py +++ mistral-vibe-2.25.0/vibe/core/config/fingerprint.py @@ -27,10 +27,35 @@ def capture_stable_file(path: Path) -> I raise ConcurrencyConflictError(expected_fp=before, actual_fp=after) +_FINGERPRINT_CHUNK_SIZE = 1 << 16 + + def create_file_fingerprint(file: IO) -> str: - """Return an opaque token representing the current state of a file.""" - stat = os.fstat(file.fileno()) - return f"{stat.st_dev}:{stat.st_ino}:{stat.st_mtime_ns}:{stat.st_size}" + """Return an opaque token representing the current state of a file. + + The token covers both the file's identity and its contents. Identity alone + is not sufficient: replacing a file's contents with different data of the + same length within a single filesystem timestamp tick leaves st_size, + st_mtime_ns and st_ctime_ns all unchanged (both timestamps come from the + same clock), so a stat-only token cannot observe the change and a config + reload silently keeps serving stale values. + + Contents are read with os.pread() so that the caller's file position is + left untouched -- capture_stable_file() hands the same open file to its + caller -- and so that the O_RDWR handle from tempfile.NamedTemporaryFile() + used by the atomic-write path can be fingerprinted as well. + """ + fd = file.fileno() + stat = os.fstat(fd) + digest = hashlib.sha256() + offset = 0 + while chunk := os.pread(fd, _FINGERPRINT_CHUNK_SIZE, offset): + digest.update(chunk) + offset += len(chunk) + return ( + f"{stat.st_dev}:{stat.st_ino}:{stat.st_mtime_ns}:{stat.st_size}" + f":{digest.hexdigest()}" + ) def create_dict_fingerprint(source: dict[str, Any]) -> str: ++++++ fix_ui_tests.patch ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.182822465 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.186822631 +0200 @@ -7,11 +7,11 @@ tests/test_ui_rewind.py | 2 ++ 6 files changed, 20 insertions(+), 2 deletions(-) -Index: mistral-vibe-2.24.3/tests/app_server/test_vibe_code.py +Index: mistral-vibe-2.25.0/tests/app_server/test_vibe_code.py =================================================================== ---- mistral-vibe-2.24.3.orig/tests/app_server/test_vibe_code.py 2026-08-22 13:42:42.936887544 +0200 -+++ mistral-vibe-2.24.3/tests/app_server/test_vibe_code.py 2026-08-22 13:44:23.769739837 +0200 -@@ -68,7 +68,7 @@ +--- mistral-vibe-2.25.0.orig/tests/app_server/test_vibe_code.py ++++ mistral-vibe-2.25.0/tests/app_server/test_vibe_code.py +@@ -68,7 +68,7 @@ def test_app_server_import_does_not_requ capture_output=True, env=env, text=True, @@ -20,10 +20,10 @@ ) assert result.returncode == 0, result.stderr -Index: mistral-vibe-2.24.3/tests/cli/test_ui_config_and_model_picker.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py =================================================================== ---- mistral-vibe-2.24.3.orig/tests/cli/test_ui_config_and_model_picker.py 2026-08-22 13:44:10.539665525 +0200 -+++ mistral-vibe-2.24.3/tests/cli/test_ui_config_and_model_picker.py 2026-08-22 13:44:23.770218219 +0200 +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_config_and_model_picker.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py @@ -1,5 +1,6 @@ from __future__ import annotations @@ -31,8 +31,8 @@ from unittest.mock import AsyncMock, patch import pytest -@@ -41,6 +42,15 @@ - return build_test_vibe_config(models=_model_configs(), active_model="", **kwargs) +@@ -52,6 +53,15 @@ async def _open_model_picker(pilot, app) + return picker +async def _wait_until_drained(pilot, app, timeout: float = 2.0) -> bool: @@ -47,20 +47,20 @@ # --- /model command --- -@@ -263,7 +273,7 @@ - # Highlight starts on pinned "alpha" (index 1); move up to Default. - await pilot.press("up") +@@ -181,7 +191,7 @@ async def test_model_picker_select_curre + await _open_model_picker(pilot, app) + await pilot.press("enter") - await pilot.pause(0.2) + assert await _wait_until_drained(pilot, app) - assert app.config.active_model_pinned is False + assert app.config.active_model.alias == "alpha" assert app._current_bottom_app == BottomApp.Input -Index: mistral-vibe-2.24.3/tests/cli/test_ui_session_incremental_renderer.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_session_incremental_renderer.py =================================================================== ---- mistral-vibe-2.24.3.orig/tests/cli/test_ui_session_incremental_renderer.py 2026-08-22 13:42:42.936887544 +0200 -+++ mistral-vibe-2.24.3/tests/cli/test_ui_session_incremental_renderer.py 2026-08-22 13:44:23.770518335 +0200 -@@ -5,6 +5,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_session_incremental_renderer.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_session_incremental_renderer.py +@@ -5,6 +5,8 @@ from pathlib import Path import time import pytest @@ -69,24 +69,24 @@ from textual.widgets import Button from tests.conftest import build_test_agent_loop -Index: mistral-vibe-2.24.3/tests/cli/test_ui_skill_dispatch.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_skill_dispatch.py =================================================================== ---- mistral-vibe-2.24.3.orig/tests/cli/test_ui_skill_dispatch.py 2026-08-22 13:42:42.936887544 +0200 -+++ mistral-vibe-2.24.3/tests/cli/test_ui_skill_dispatch.py 2026-08-22 13:44:23.770763718 +0200 -@@ -7,6 +7,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_skill_dispatch.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_skill_dispatch.py +@@ -8,6 +8,8 @@ from weakref import WeakKeyDictionary import pytest +pytestmark = pytest.mark.terminal + - from tests.conftest import build_test_vibe_app, build_test_vibe_config - from tests.skills.conftest import create_skill - from vibe.app_server.models import CompletedEffectState, PublicEffectEntry -Index: mistral-vibe-2.24.3/tests/cli/textual_ui/test_app_server_requests.py -=================================================================== ---- mistral-vibe-2.24.3.orig/tests/cli/textual_ui/test_app_server_requests.py 2026-08-22 13:42:42.936887544 +0200 -+++ mistral-vibe-2.24.3/tests/cli/textual_ui/test_app_server_requests.py 2026-08-22 13:44:23.771035260 +0200 -@@ -8,6 +8,8 @@ + from tests.conftest import ( + build_test_agent_loop, + build_test_vibe_app, +Index: mistral-vibe-2.25.0/tests/cli/textual_ui/test_app_server_requests.py +=================================================================== +--- mistral-vibe-2.25.0.orig/tests/cli/textual_ui/test_app_server_requests.py ++++ mistral-vibe-2.25.0/tests/cli/textual_ui/test_app_server_requests.py +@@ -8,6 +8,8 @@ from unittest.mock import AsyncMock, Mag import pytest @@ -95,11 +95,11 @@ from tests.conftest import ( build_test_agent_loop, build_test_vibe_app, -Index: mistral-vibe-2.24.3/tests/test_ui_rewind.py +Index: mistral-vibe-2.25.0/tests/test_ui_rewind.py =================================================================== ---- mistral-vibe-2.24.3.orig/tests/test_ui_rewind.py 2026-08-22 13:42:42.936887544 +0200 -+++ mistral-vibe-2.24.3/tests/test_ui_rewind.py 2026-08-22 13:44:23.771389237 +0200 -@@ -6,6 +6,8 @@ +--- mistral-vibe-2.25.0.orig/tests/test_ui_rewind.py ++++ mistral-vibe-2.25.0/tests/test_ui_rewind.py +@@ -6,6 +6,8 @@ import time import pytest ++++++ mistral-vibe-2.24.5.tar.gz -> mistral-vibe-2.25.0.tar.gz ++++++ ++++ 63567 lines of diff (skipped) ++++++ no_network.patch ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.885851760 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.889851927 +0200 @@ -16,11 +16,11 @@ tests/test_install_script.py | 3 +++ 15 files changed, 36 insertions(+) -Index: mistral-vibe-2.24.4/pyproject.toml +Index: mistral-vibe-2.25.0/pyproject.toml =================================================================== ---- mistral-vibe-2.24.4.orig/pyproject.toml 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/pyproject.toml 2026-08-27 15:09:33.762522932 +0200 -@@ -272,6 +272,7 @@ +--- mistral-vibe-2.25.0.orig/pyproject.toml ++++ mistral-vibe-2.25.0/pyproject.toml +@@ -272,6 +272,7 @@ addopts = "-p pytest_vibe -vvvv -q -n au timeout = 10 markers = [ "unified_supported: backend contract behavior implemented by the Unified Harness", @@ -28,11 +28,11 @@ ] filterwarnings = [ # (e2e) streaming mock server is started in a thread; and the cli is spawn in a fork -Index: mistral-vibe-2.24.4/tests/acp/test_acp_entrypoint_smoke.py +Index: mistral-vibe-2.25.0/tests/acp/test_acp_entrypoint_smoke.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/acp/test_acp_entrypoint_smoke.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/acp/test_acp_entrypoint_smoke.py 2026-08-27 09:57:37.157045175 +0200 -@@ -29,6 +29,8 @@ +--- mistral-vibe-2.25.0.orig/tests/acp/test_acp_entrypoint_smoke.py ++++ mistral-vibe-2.25.0/tests/acp/test_acp_entrypoint_smoke.py +@@ -29,6 +29,8 @@ BROWSER_AUTH_DESCRIPTION = ( "Sign into Mistral Vibe through your Mistral AI Studio account." ) @@ -41,11 +41,11 @@ class _AcpSmokeClient(Client): def on_connect(self, conn: Any) -> None: -Index: mistral-vibe-2.24.4/tests/app_server/test_transport.py +Index: mistral-vibe-2.25.0/tests/app_server/test_transport.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/app_server/test_transport.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/app_server/test_transport.py 2026-08-27 09:57:37.157476994 +0200 -@@ -239,6 +239,7 @@ +--- mistral-vibe-2.25.0.orig/tests/app_server/test_transport.py ++++ mistral-vibe-2.25.0/tests/app_server/test_transport.py +@@ -240,6 +240,7 @@ async def test_stdio_transport_close_is_ assert [json.loads(line) for line in writer.getvalue().splitlines()] == [{"id": 1}] @@ -53,19 +53,19 @@ @pytest.mark.asyncio async def test_stdio_server_uses_the_same_json_rpc_lifecycle() -> None: agent_loop = build_test_agent_loop() -Index: mistral-vibe-2.24.4/tests/cli/test_audio_config_boundary.py +Index: mistral-vibe-2.25.0/tests/cli/test_audio_config_boundary.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_audio_config_boundary.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_audio_config_boundary.py 2026-08-27 09:57:37.157833971 +0200 -@@ -29,6 +29,7 @@ - return await _wait_until(pilot, lambda: not app._queue.draining, timeout) +--- mistral-vibe-2.25.0.orig/tests/cli/test_audio_config_boundary.py ++++ mistral-vibe-2.25.0/tests/cli/test_audio_config_boundary.py +@@ -9,6 +9,7 @@ from tests.stubs.fake_voice_manager impo + from vibe.cli.narrator_manager import NarratorState [email protected] @pytest.mark.asyncio async def test_voice_mode_is_persisted_before_local_application() -> None: voice = FakeVoiceManager(is_voice_ready=False) -@@ -60,6 +61,7 @@ +@@ -37,6 +38,7 @@ async def test_voice_mode_is_persisted_b assert voice.is_enabled is True @@ -73,7 +73,7 @@ @pytest.mark.asyncio async def test_local_voice_failure_does_not_undo_accepted_config() -> None: voice = FakeVoiceManager(is_voice_ready=False) -@@ -84,6 +86,7 @@ +@@ -60,6 +62,7 @@ async def test_local_voice_failure_does_ assert notify.call_args.kwargs["severity"] == "warning" @@ -81,11 +81,11 @@ @pytest.mark.asyncio async def test_narrator_sync_observes_accepted_config() -> None: narrator = MagicMock() -Index: mistral-vibe-2.24.4/tests/cli/test_log_level_command.py +Index: mistral-vibe-2.25.0/tests/cli/test_log_level_command.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_log_level_command.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_log_level_command.py 2026-08-27 09:57:37.158153357 +0200 -@@ -199,6 +199,7 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_log_level_command.py ++++ mistral-vibe-2.25.0/tests/cli/test_log_level_command.py +@@ -199,6 +199,7 @@ async def test_picker_session_cleared_sh assert get_session_override() is None @@ -93,11 +93,11 @@ @pytest.mark.asyncio async def test_picker_config_write_failure_surfaces_error(monkeypatch) -> None: # When the inline (idle) config write fails, the picker must surface an -Index: mistral-vibe-2.24.4/tests/cli/test_ui_config_and_model_picker.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_config_and_model_picker.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_config_and_model_picker.py 2026-08-27 15:09:33.762522932 +0200 -@@ -145,6 +145,7 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_config_and_model_picker.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py +@@ -151,6 +151,7 @@ async def test_model_picker_escape_does_ update_config.assert_not_awaited() @@ -105,11 +105,11 @@ @pytest.mark.asyncio async def test_model_picker_select_model() -> None: app = build_test_vibe_app(config=_make_config_with_models()) -Index: mistral-vibe-2.24.4/tests/cli/textual_ui/test_custom_tools_deprecation.py +Index: mistral-vibe-2.25.0/tests/cli/textual_ui/test_custom_tools_deprecation.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/textual_ui/test_custom_tools_deprecation.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/textual_ui/test_custom_tools_deprecation.py 2026-08-27 09:57:37.158693942 +0200 -@@ -21,6 +21,7 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/textual_ui/test_custom_tools_deprecation.py ++++ mistral-vibe-2.25.0/tests/cli/textual_ui/test_custom_tools_deprecation.py +@@ -21,6 +21,7 @@ async def _wait_for(predicate: Callable[ pytest.fail("Condition not met within timeout") @@ -117,7 +117,7 @@ @pytest.mark.asyncio async def test_startup_warns_when_custom_tools_are_available(tmp_path: Path) -> None: tools_dir = tmp_path / "tools" -@@ -69,6 +70,7 @@ +@@ -69,6 +70,7 @@ async def test_startup_does_not_warn_wit assert not app.query(CustomToolsDeprecationMessage) @@ -125,11 +125,11 @@ @pytest.mark.asyncio async def test_rebuilding_the_transcript_restores_the_custom_tools_warning( tmp_path: Path, -Index: mistral-vibe-2.24.4/tests/conftest.py +Index: mistral-vibe-2.25.0/tests/conftest.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/conftest.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/conftest.py 2026-08-27 15:14:18.316888893 +0200 -@@ -237,6 +237,17 @@ +--- mistral-vibe-2.25.0.orig/tests/conftest.py ++++ mistral-vibe-2.25.0/tests/conftest.py +@@ -238,6 +238,17 @@ def _mock_api_key(monkeypatch: pytest.Mo @pytest.fixture(autouse=True) @@ -147,11 +147,11 @@ def _mock_platform(monkeypatch: pytest.MonkeyPatch) -> None: """Mock platform to be Linux with /bin/sh shell for consistent test behavior. -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_fresh_install.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_fresh_install.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_fresh_install.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_fresh_install.py 2026-08-27 09:57:37.159243674 +0200 -@@ -62,6 +62,7 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_fresh_install.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_fresh_install.py +@@ -62,6 +62,7 @@ def _install_fresh_wheel(tmp_path: Path, return _venv_executable(venv_path, "vibe") @@ -159,11 +159,11 @@ @pytest.mark.timeout(90) def test_fresh_wheel_install_can_spawn_cli_and_complete_happy_path( streaming_mock_server: StreamingMockServer, -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_hooks.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_hooks.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_hooks.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_hooks.py 2026-08-27 09:57:37.159496414 +0200 -@@ -18,6 +18,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_hooks.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_hooks.py +@@ -18,6 +18,8 @@ from tests.e2e.common import ( ) from tests.e2e.mock_server import StreamingMockServer @@ -172,11 +172,11 @@ def _setup_recording_hook(vibe_home: Path, invocation_path: Path) -> None: script = vibe_home / "_record_hook.py" -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_onboarding.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_onboarding.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_onboarding.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_onboarding.py 2026-08-27 09:57:37.159696533 +0200 -@@ -7,6 +7,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_onboarding.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_onboarding.py +@@ -7,6 +7,8 @@ import pytest from tests.e2e.common import SpawnedVibeProcessFixture, ansi_tolerant_pattern @@ -185,11 +185,11 @@ @pytest.mark.timeout(15) def test_spawn_cli_shows_onboarding_when_api_key_missing( -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_session_exit.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_session_exit.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_session_exit.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_session_exit.py 2026-08-27 09:57:37.159895881 +0200 -@@ -24,6 +24,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_session_exit.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_session_exit.py +@@ -24,6 +24,8 @@ from tests.e2e.common import ( from tests.e2e.mock_server import StreamingMockServer from vibe.utils.io import read_safe @@ -198,11 +198,11 @@ def _usage_by_run_factory( request_index: int, _payload: object -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_streaming.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_streaming.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_streaming.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_streaming.py 2026-08-27 09:57:37.160090270 +0200 -@@ -14,6 +14,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_streaming.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_streaming.py +@@ -14,6 +14,8 @@ from tests.e2e.common import ( ) from tests.e2e.mock_server import StreamingMockServer @@ -211,11 +211,11 @@ @pytest.mark.timeout(15) def test_spawn_cli_to_send_and_receive_message( -Index: mistral-vibe-2.24.4/tests/e2e/test_cli_tui_tool_approval.py +Index: mistral-vibe-2.25.0/tests/e2e/test_cli_tui_tool_approval.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/test_cli_tui_tool_approval.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/test_cli_tui_tool_approval.py 2026-08-27 09:57:37.160281803 +0200 -@@ -14,6 +14,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/test_cli_tui_tool_approval.py ++++ mistral-vibe-2.25.0/tests/e2e/test_cli_tui_tool_approval.py +@@ -14,6 +14,8 @@ from tests.e2e.common import ( ) from tests.e2e.mock_server import ChatCompletionsRequestPayload, StreamingMockServer @@ -224,11 +224,11 @@ PREDICTABLE_OUTPUT = "__E2E_BASH_OK__" TOOL_ARGUMENTS = f'{{"command":"printf \\"{PREDICTABLE_OUTPUT}\\\\n\\""}}' -Index: mistral-vibe-2.24.4/tests/test_install_script.py +Index: mistral-vibe-2.25.0/tests/test_install_script.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/test_install_script.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/test_install_script.py 2026-08-27 09:57:37.160559720 +0200 -@@ -7,6 +7,8 @@ +--- mistral-vibe-2.25.0.orig/tests/test_install_script.py ++++ mistral-vibe-2.25.0/tests/test_install_script.py +@@ -7,6 +7,8 @@ import stat import subprocess from textwrap import dedent @@ -237,7 +237,7 @@ INSTALL_SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "install.sh" -@@ -146,6 +148,7 @@ +@@ -146,6 +148,7 @@ def _run_install_script( ) ++++++ no_terminal.patch ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.919853177 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.925853427 +0200 @@ -5,7 +5,7 @@ tests/cli/test_switching_mode.py | 2 ++ tests/cli/test_ui_clipboard_notifications.py | 2 ++ tests/cli/test_ui_config_and_model_picker.py | 3 +++ - tests/cli/test_ui_config_screen.py | 2 ++ + tests/cli/test_ui_config_screen.py | 3 +++ tests/cli/test_ui_exit_command.py | 2 ++ tests/cli/test_ui_theme_picker.py | 2 ++ tests/cli/test_whoami_command.py | 2 ++ @@ -20,12 +20,12 @@ tests/onboarding/test_ui_onboarding.py | 2 ++ tests/tools/test_ui_bash_execution.py | 2 ++ tests/vscode_extension_promo/test_ui_vscode_extension_promo.py | 2 ++ - 19 files changed, 38 insertions(+) -Index: mistral-vibe-2.24.4/pyproject.toml + 19 files changed, 39 insertions(+) +Index: mistral-vibe-2.25.0/pyproject.toml =================================================================== ---- mistral-vibe-2.24.4.orig/pyproject.toml 2026-08-27 09:57:37.156721782 +0200 -+++ mistral-vibe-2.24.4/pyproject.toml 2026-08-27 09:57:43.320690567 +0200 -@@ -273,6 +273,7 @@ +--- mistral-vibe-2.25.0.orig/pyproject.toml ++++ mistral-vibe-2.25.0/pyproject.toml +@@ -273,6 +273,7 @@ timeout = 10 markers = [ "unified_supported: backend contract behavior implemented by the Unified Harness", "network: tests that require network-capable execution environment", @@ -33,11 +33,11 @@ ] filterwarnings = [ # (e2e) streaming mock server is started in a thread; and the cli is spawn in a fork -Index: mistral-vibe-2.24.4/tests/cli/test_switching_mode.py +Index: mistral-vibe-2.25.0/tests/cli/test_switching_mode.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_switching_mode.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_switching_mode.py 2026-08-27 09:57:43.320988152 +0200 -@@ -5,6 +5,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_switching_mode.py ++++ mistral-vibe-2.25.0/tests/cli/test_switching_mode.py +@@ -5,6 +5,8 @@ from unittest.mock import patch import pytest @@ -46,11 +46,11 @@ from tests.conftest import build_test_agent_loop, build_test_vibe_app from tests.mock.utils import mock_llm_chunk from tests.stubs.fake_backend import FakeBackend -Index: mistral-vibe-2.24.4/tests/cli/test_ui_clipboard_notifications.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_clipboard_notifications.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_clipboard_notifications.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_clipboard_notifications.py 2026-08-27 09:57:43.321270718 +0200 -@@ -3,6 +3,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_clipboard_notifications.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_clipboard_notifications.py +@@ -3,6 +3,8 @@ from __future__ import annotations from unittest.mock import patch import pytest @@ -59,11 +59,11 @@ from textual.selection import Selection from textual.widget import Widget -Index: mistral-vibe-2.24.4/tests/cli/test_ui_config_and_model_picker.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_config_and_model_picker.py 2026-08-27 09:57:37.158402940 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_config_and_model_picker.py 2026-08-27 09:57:43.321469515 +0200 -@@ -3,6 +3,9 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_config_and_model_picker.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_config_and_model_picker.py +@@ -3,6 +3,9 @@ from __future__ import annotations from unittest.mock import AsyncMock, patch import pytest @@ -72,25 +72,26 @@ + from textual.widgets import OptionList - from tests.conftest import build_test_vibe_app, build_test_vibe_config -Index: mistral-vibe-2.24.4/tests/cli/test_ui_config_screen.py + from tests.conftest import build_test_vibe_app, build_test_vibe_config, wait_until +Index: mistral-vibe-2.25.0/tests/cli/test_ui_config_screen.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_config_screen.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_config_screen.py 2026-08-27 09:57:43.321715491 +0200 -@@ -4,6 +4,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_config_screen.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_config_screen.py +@@ -4,6 +4,9 @@ from pathlib import Path import tomllib import pytest + +pytestmark = pytest.mark.terminal ++ + from textual.pilot import Pilot import tomli_w - from tests.conftest import ( -Index: mistral-vibe-2.24.4/tests/cli/test_ui_exit_command.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_exit_command.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_exit_command.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_exit_command.py 2026-08-27 09:57:43.321933444 +0200 -@@ -4,6 +4,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_exit_command.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_exit_command.py +@@ -4,6 +4,8 @@ from typing import Any import pytest @@ -99,11 +100,11 @@ from tests.conftest import build_test_vibe_app from vibe.cli.textual_ui.widgets.chat_input.container import ChatInputContainer from vibe.cli.textual_ui.widgets.messages import SlashCommandMessage, UserMessage -Index: mistral-vibe-2.24.4/tests/cli/test_ui_theme_picker.py +Index: mistral-vibe-2.25.0/tests/cli/test_ui_theme_picker.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_ui_theme_picker.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_ui_theme_picker.py 2026-08-27 09:57:43.322155054 +0200 -@@ -7,6 +7,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_ui_theme_picker.py ++++ mistral-vibe-2.25.0/tests/cli/test_ui_theme_picker.py +@@ -7,6 +7,8 @@ from unittest.mock import AsyncMock, Moc import pytest @@ -112,11 +113,11 @@ from tests.conftest import build_test_vibe_app, build_test_vibe_config from vibe.cli.textual_ui.app import BottomApp from vibe.cli.textual_ui.widgets.theme_picker import ThemePickerApp -Index: mistral-vibe-2.24.4/tests/cli/test_whoami_command.py +Index: mistral-vibe-2.25.0/tests/cli/test_whoami_command.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_whoami_command.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_whoami_command.py 2026-08-27 09:57:43.322376424 +0200 -@@ -4,6 +4,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_whoami_command.py ++++ mistral-vibe-2.25.0/tests/cli/test_whoami_command.py +@@ -4,6 +4,8 @@ import asyncio import pytest @@ -125,11 +126,11 @@ from tests.conftest import build_test_vibe_app from tests.stubs.fake_account_gateway import FakeAccountGateway from tests.stubs.fake_identity_gateway import FakeIdentityGateway -Index: mistral-vibe-2.24.4/tests/cli/test_word_selection.py +Index: mistral-vibe-2.25.0/tests/cli/test_word_selection.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/test_word_selection.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/test_word_selection.py 2026-08-27 09:57:43.322622130 +0200 -@@ -3,6 +3,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_word_selection.py ++++ mistral-vibe-2.25.0/tests/cli/test_word_selection.py +@@ -3,6 +3,8 @@ from __future__ import annotations from typing import Any, ClassVar, cast import pytest @@ -138,10 +139,10 @@ from textual import events from textual.geometry import Offset, Region from textual.screen import Screen -Index: mistral-vibe-2.24.4/tests/cli/textual_ui/test_chat_input_word_drag.py +Index: mistral-vibe-2.25.0/tests/cli/textual_ui/test_chat_input_word_drag.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/textual_ui/test_chat_input_word_drag.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/textual_ui/test_chat_input_word_drag.py 2026-08-27 09:57:43.322933020 +0200 +--- mistral-vibe-2.25.0.orig/tests/cli/textual_ui/test_chat_input_word_drag.py ++++ mistral-vibe-2.25.0/tests/cli/textual_ui/test_chat_input_word_drag.py @@ -1,6 +1,8 @@ from __future__ import annotations @@ -151,24 +152,24 @@ from textual import events from textual.widgets.text_area import Selection -Index: mistral-vibe-2.24.4/tests/cli/textual_ui/test_message_queue_ui.py +Index: mistral-vibe-2.25.0/tests/cli/textual_ui/test_message_queue_ui.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/cli/textual_ui/test_message_queue_ui.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/cli/textual_ui/test_message_queue_ui.py 2026-08-27 09:57:43.323195167 +0200 -@@ -5,6 +5,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/textual_ui/test_message_queue_ui.py ++++ mistral-vibe-2.25.0/tests/cli/textual_ui/test_message_queue_ui.py +@@ -6,6 +6,8 @@ import time import pytest +pytestmark = pytest.mark.terminal + - from tests.conftest import build_test_vibe_app - from vibe.cli.textual_ui.app import VibeApp - from vibe.cli.textual_ui.widgets.chat_input.container import ChatInputContainer -Index: mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_resume.py + from tests.conftest import build_test_agent_loop, build_test_vibe_app + from tests.mock.utils import mock_llm_chunk + from tests.stubs.fake_backend import FakeBackend +Index: mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_resume.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/agent_loop_characterization/test_resume.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_resume.py 2026-08-27 09:57:43.323455320 +0200 -@@ -8,6 +8,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/agent_loop_characterization/test_resume.py ++++ mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_resume.py +@@ -8,6 +8,8 @@ import time import pexpect import pytest @@ -177,11 +178,11 @@ from tests.e2e.agent_loop_characterization.support import ( assert_assistant_tool_call_present, assert_message_content_present, -Index: mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_subagents.py +Index: mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_subagents.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/agent_loop_characterization/test_subagents.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_subagents.py 2026-08-27 09:57:43.323736183 +0200 -@@ -5,6 +5,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/agent_loop_characterization/test_subagents.py ++++ mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_subagents.py +@@ -5,6 +5,8 @@ from pathlib import Path import pexpect import pytest @@ -190,11 +191,11 @@ from tests.e2e.agent_loop_characterization.support import ( assert_message_content_present, assert_tool_result_contains, -Index: mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_tool_execution.py +Index: mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_tool_execution.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/agent_loop_characterization/test_tool_execution.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_tool_execution.py 2026-08-27 09:57:43.323911806 +0200 -@@ -6,6 +6,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/agent_loop_characterization/test_tool_execution.py ++++ mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_tool_execution.py +@@ -6,6 +6,8 @@ from pathlib import Path import pexpect import pytest @@ -203,11 +204,11 @@ from tests.e2e.agent_loop_characterization.support import ( answer_approval, assert_assistant_tool_call_present, -Index: mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_tool_permissions.py +Index: mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_tool_permissions.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/agent_loop_characterization/test_tool_permissions.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_tool_permissions.py 2026-08-27 09:57:43.324095464 +0200 -@@ -6,6 +6,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/agent_loop_characterization/test_tool_permissions.py ++++ mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_tool_permissions.py +@@ -6,6 +6,8 @@ from pathlib import Path import pexpect import pytest @@ -216,11 +217,11 @@ from tests.e2e.agent_loop_characterization.support import ( answer_approval, assert_tool_result_contains, -Index: mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_user_interaction.py +Index: mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_user_interaction.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/e2e/agent_loop_characterization/test_user_interaction.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/e2e/agent_loop_characterization/test_user_interaction.py 2026-08-27 09:57:43.324278411 +0200 -@@ -7,6 +7,8 @@ +--- mistral-vibe-2.25.0.orig/tests/e2e/agent_loop_characterization/test_user_interaction.py ++++ mistral-vibe-2.25.0/tests/e2e/agent_loop_characterization/test_user_interaction.py +@@ -7,6 +7,8 @@ import time import pexpect import pytest @@ -229,11 +230,11 @@ from tests.e2e.agent_loop_characterization.support import ( APPROVAL_INPUT_GRACE_PERIOD_S, assert_tool_result_contains, -Index: mistral-vibe-2.24.4/tests/onboarding/test_ui_onboarding.py +Index: mistral-vibe-2.25.0/tests/onboarding/test_ui_onboarding.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/onboarding/test_ui_onboarding.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/onboarding/test_ui_onboarding.py 2026-08-27 09:57:43.324532673 +0200 -@@ -10,6 +10,8 @@ +--- mistral-vibe-2.25.0.orig/tests/onboarding/test_ui_onboarding.py ++++ mistral-vibe-2.25.0/tests/onboarding/test_ui_onboarding.py +@@ -10,6 +10,8 @@ from unittest.mock import MagicMock, pat import keyring from keyring.errors import KeyringError import pytest @@ -242,11 +243,11 @@ from textual.content import Content from textual.events import Resize from textual.geometry import Size -Index: mistral-vibe-2.24.4/tests/tools/test_ui_bash_execution.py +Index: mistral-vibe-2.25.0/tests/tools/test_ui_bash_execution.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/tools/test_ui_bash_execution.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/tools/test_ui_bash_execution.py 2026-08-27 09:57:43.324865304 +0200 -@@ -5,6 +5,8 @@ +--- mistral-vibe-2.25.0.orig/tests/tools/test_ui_bash_execution.py ++++ mistral-vibe-2.25.0/tests/tools/test_ui_bash_execution.py +@@ -5,6 +5,8 @@ import time from pydantic import JsonValue import pytest @@ -255,11 +256,11 @@ from tests.conftest import build_test_agent_loop, build_test_vibe_app from tests.mock.utils import mock_llm_chunk from tests.stubs.fake_backend import FakeBackend -Index: mistral-vibe-2.24.4/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py +Index: mistral-vibe-2.25.0/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py =================================================================== ---- mistral-vibe-2.24.4.orig/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py 2026-08-26 17:18:33.000000000 +0200 -+++ mistral-vibe-2.24.4/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py 2026-08-27 09:57:43.325114777 +0200 -@@ -8,6 +8,8 @@ +--- mistral-vibe-2.25.0.orig/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py ++++ mistral-vibe-2.25.0/tests/vscode_extension_promo/test_ui_vscode_extension_promo.py +@@ -8,6 +8,8 @@ from unittest.mock import patch import pytest ++++++ obs-test-synchronization.patch ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.947854343 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.951854510 +0200 @@ -1,8 +1,8 @@ -Index: mistral-vibe-2.24.5/tests/cli/test_connector_auth_app.py +Index: mistral-vibe-2.25.0/tests/cli/test_connector_auth_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/tests/cli/test_connector_auth_app.py 2026-08-31 08:24:47.483883761 +0200 -+++ mistral-vibe-2.24.5/tests/cli/test_connector_auth_app.py 2026-08-31 08:24:47.498852360 +0200 -@@ -253,8 +253,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_connector_auth_app.py ++++ mistral-vibe-2.25.0/tests/cli/test_connector_auth_app.py +@@ -253,8 +253,8 @@ class TestCloseAndRefresh: async def test_action_refresh_dispatches_worker(self) -> None: app = _make_app() @@ -13,11 +13,11 @@ app.run_worker = MagicMock(side_effect=close_worker) app.query_one = MagicMock() -Index: mistral-vibe-2.24.5/tests/cli/test_mcp_app.py +Index: mistral-vibe-2.25.0/tests/cli/test_mcp_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/tests/cli/test_mcp_app.py 2026-08-31 08:24:45.830139052 +0200 -+++ mistral-vibe-2.24.5/tests/cli/test_mcp_app.py 2026-08-31 08:24:47.499468230 +0200 -@@ -425,8 +425,8 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_mcp_app.py ++++ mistral-vibe-2.25.0/tests/cli/test_mcp_app.py +@@ -433,8 +433,8 @@ def test_refresh_index_replaces_state_fr def test_start_refresh_dispatches_one_worker() -> None: app = MCPApp(_state(), refresh_callback=AsyncMock(return_value="Refreshed")) @@ -28,87 +28,11 @@ app.run_worker = MagicMock(side_effect=close_worker) -Index: mistral-vibe-2.24.5/tests/cli/textual_ui/test_queue_selection_ui.py +Index: mistral-vibe-2.25.0/tests/update_notifier/test_ui_update_notification.py =================================================================== ---- mistral-vibe-2.24.5.orig/tests/cli/textual_ui/test_queue_selection_ui.py 2026-08-31 08:24:45.830139052 +0200 -+++ mistral-vibe-2.24.5/tests/cli/textual_ui/test_queue_selection_ui.py 2026-09-02 07:54:45.031953978 +0200 -@@ -627,19 +627,18 @@ - # items so the drain consumes them by running the shell (no LLM turn). - async with vibe_app.run_test() as pilot: - chat_input = vibe_app.query_one(ChatInputContainer) -- chat_input.value = "!sleep 2" -+ chat_input.value = "!sleep 10" - await pilot.press("enter") - assert await _wait_until( - pilot, lambda: vibe_app._bash_task is not None, timeout=2.0 - ) - -- chat_input.value = "!sleep 1" -+ chat_input.value = "!sleep 10" - await pilot.press("enter") -- await pilot.pause(0.05) -+ assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 1, timeout=6.0) - chat_input.value = "!echo newest" - await pilot.press("enter") -- await pilot.pause(0.05) -- assert len(vibe_app._queue) == 2 -+ assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 2, timeout=6.0) - - body = vibe_app.query_one(ChatInputContainer)._body - assert body is not None -@@ -647,16 +646,15 @@ - # Highlight the OLDEST item (the one the drain consumes first, FIFO). - # newest-first list: cursor 0 = newest, cursor 1 = oldest. - await pilot.press("up") -- await pilot.pause(0.1) -+ assert await _wait_until(pilot, lambda: body._queue_cursor == 0, timeout=6.0) - await pilot.press("up") -- await pilot.pause(0.1) -- assert body._queue_cursor == 1 -+ assert await _wait_until(pilot, lambda: body._queue_cursor == 1, timeout=6.0) - assert vibe_app._queue_selected_widget is not None - - # Blocking bash finishes, drain consumes the highlighted oldest bash - # (FIFO) — the highlighted widget is removed but _queue_selected_widget - # still points at it until the next resync re-posts the scroll. -- assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 1, timeout=6.0) -+ assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 1, timeout=15.0) - # Re-sync via navigation hits the clamp branch (highlighted widget gone); - # the fix re-posts the scroll so _queue_selected_widget re-points at the - # surviving newest item. Without it, Backspace below no-ops. -@@ -677,7 +675,7 @@ - ) -> None: - async with vibe_app.run_test() as pilot: - chat_input = vibe_app.query_one(ChatInputContainer) -- chat_input.value = "!sleep 2" -+ chat_input.value = "!sleep 10" - await pilot.press("enter") - assert await _wait_until( - pilot, lambda: vibe_app._bash_task is not None, timeout=2.0 -@@ -693,14 +691,14 @@ - - # Enter edit mode on the bash item while the app is still busy. - await pilot.press("up") -- await pilot.pause(0.1) -+ assert await _wait_until(pilot, lambda: vibe_app._queue_selected_widget is not None, timeout=6.0) -+ assert await _wait_until(pilot, lambda: body._queue_cursor == 0, timeout=6.0) - await pilot.press("enter") -- await pilot.pause(0.1) -- assert body._queue_in_edit_mode -+ assert await _wait_until(pilot, lambda: body._queue_in_edit_mode, timeout=6.0) - assert body._queue_edit_kind == QueuedItemKind.BASH - - # Wait for the drain to consume the queued bash item. -- assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 0, timeout=6.0) -+ assert await _wait_until(pilot, lambda: len(vibe_app._queue) == 0, timeout=15.0) - - assert body.input_widget is not None - body.input_widget.clear_text() -Index: mistral-vibe-2.24.5/tests/update_notifier/test_ui_update_notification.py -=================================================================== ---- mistral-vibe-2.24.5.orig/tests/update_notifier/test_ui_update_notification.py 2026-08-31 08:24:45.830139052 +0200 -+++ mistral-vibe-2.24.5/tests/update_notifier/test_ui_update_notification.py 2026-08-31 08:25:48.175638232 +0200 -@@ -28,6 +28,15 @@ +--- mistral-vibe-2.25.0.orig/tests/update_notifier/test_ui_update_notification.py ++++ mistral-vibe-2.25.0/tests/update_notifier/test_ui_update_notification.py +@@ -28,6 +28,15 @@ from vibe.core.config import VibeConfigS TEST_CURRENT_VERSION = "0.1.0" @@ -124,7 +48,7 @@ @pytest.fixture def build_update_test_app( vibe_config_with_update_checks_enabled: VibeConfigSchema, -@@ -79,6 +88,7 @@ +@@ -79,6 +88,7 @@ async def test_ui_writes_pending_update_ ) async with app.run_test() as pilot: @@ -132,7 +56,7 @@ await _assert_no_notifications(app, pilot, timeout=0.3) assert notifier.fetch_update_calls == 1 -@@ -91,9 +101,15 @@ +@@ -91,9 +101,15 @@ async def test_ui_does_not_notify_when_n build_update_test_app: Callable[..., VibeApp], ) -> None: notifier = FakeUpdateGateway(update=None) ++++++ warning_cleanup.patch ++++++ --- /var/tmp/diff_new_pack.8Qm2cD/_old 2026-09-09 16:22:16.967855177 +0200 +++ /var/tmp/diff_new_pack.8Qm2cD/_new 2026-09-09 16:22:16.971855343 +0200 @@ -6,11 +6,11 @@ vibe/core/config/event_bus.py | 7 +++---- 5 files changed, 10 insertions(+), 12 deletions(-) -Index: mistral-vibe-2.24.5/tests/cli/test_connector_auth_app.py +Index: mistral-vibe-2.25.0/tests/cli/test_connector_auth_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/tests/cli/test_connector_auth_app.py 2026-08-27 17:26:03.000000000 +0200 -+++ mistral-vibe-2.24.5/tests/cli/test_connector_auth_app.py 2026-08-28 17:12:00.705219399 +0200 -@@ -263,7 +263,7 @@ +--- mistral-vibe-2.25.0.orig/tests/cli/test_connector_auth_app.py ++++ mistral-vibe-2.25.0/tests/cli/test_connector_auth_app.py +@@ -263,7 +263,7 @@ class TestCloseAndRefresh: assert app._status_message == "Refreshing connector..." app.run_worker.assert_called_once() @@ -19,11 +19,11 @@ assert kwargs["group"] == "connector_refresh" -Index: mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/connector_auth_app.py +Index: mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/connector_auth_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/vibe/cli/textual_ui/widgets/connector_auth_app.py 2026-08-27 17:26:03.000000000 +0200 -+++ mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/connector_auth_app.py 2026-08-28 17:12:00.705596550 +0200 -@@ -98,7 +98,7 @@ +--- mistral-vibe-2.25.0.orig/vibe/cli/textual_ui/widgets/connector_auth_app.py ++++ mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/connector_auth_app.py +@@ -98,7 +98,7 @@ class ConnectorAuthApp(Container): self._status_message = "Refreshing connector..." self._set_help_text(_HELP) self.run_worker( @@ -32,23 +32,23 @@ ) # ── workers ────────────────────────────────────────────────────── -Index: mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/mcp_app.py +Index: mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/mcp_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/vibe/cli/textual_ui/widgets/mcp_app.py 2026-08-27 17:26:03.000000000 +0200 -+++ mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/mcp_app.py 2026-08-28 17:12:00.706014339 +0200 -@@ -243,7 +243,7 @@ - if self._refresh_callback is None or self._refreshing: - return - self._refreshing = True -- self.run_worker(self._run_refresh(), exclusive=True, group="refresh") -+ self.run_worker(self._run_refresh, exclusive=True, group="refresh") +--- mistral-vibe-2.25.0.orig/vibe/cli/textual_ui/widgets/mcp_app.py ++++ mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/mcp_app.py +@@ -248,7 +248,7 @@ class MCPApp(Container): + # The callback owns loop-bound app-server state. Its blocking discovery + # setup is offloaded at the app-server and Runtime I/O boundaries. + self.run_worker( +- self._run_refresh(), exclusive=True, group="refresh", exit_on_error=False ++ self._run_refresh, exclusive=True, group="refresh", exit_on_error=False + ) async def _run_refresh(self) -> None: - if self._refresh_callback is not None: -Index: mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/question_app.py +Index: mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/question_app.py =================================================================== ---- mistral-vibe-2.24.5.orig/vibe/cli/textual_ui/widgets/question_app.py 2026-08-27 17:26:03.000000000 +0200 -+++ mistral-vibe-2.24.5/vibe/cli/textual_ui/widgets/question_app.py 2026-08-28 17:12:00.706455069 +0200 +--- mistral-vibe-2.25.0.orig/vibe/cli/textual_ui/widgets/question_app.py ++++ mistral-vibe-2.25.0/vibe/cli/textual_ui/widgets/question_app.py @@ -1,6 +1,5 @@ from __future__ import annotations @@ -56,7 +56,7 @@ import time from typing import TYPE_CHECKING, ClassVar -@@ -424,10 +423,10 @@ +@@ -424,10 +423,10 @@ class QuestionApp(VimNavigationMixin, Co else: new_idx = next( i @@ -71,11 +71,11 @@ if i not in self.answers ) self._switch_question(new_idx) -Index: mistral-vibe-2.24.5/vibe/core/config/event_bus.py +Index: mistral-vibe-2.25.0/vibe/core/config/event_bus.py =================================================================== ---- mistral-vibe-2.24.5.orig/vibe/core/config/event_bus.py 2026-08-27 17:26:03.000000000 +0200 -+++ mistral-vibe-2.24.5/vibe/core/config/event_bus.py 2026-08-28 17:12:00.706804558 +0200 -@@ -2,8 +2,6 @@ +--- mistral-vibe-2.25.0.orig/vibe/core/config/event_bus.py ++++ mistral-vibe-2.25.0/vibe/core/config/event_bus.py +@@ -2,8 +2,6 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass @@ -84,7 +84,7 @@ from vibe.core.config.types import ConfigChangeCallback, ConfigChangeEvent -@@ -18,7 +16,7 @@ +@@ -18,7 +16,7 @@ class Subscription: class EventBus: def __init__(self) -> None: self._subscribers: dict[int, Subscription] = {} @@ -93,7 +93,7 @@ def subscribe( self, callback: ConfigChangeCallback, *, keys: set[str] | None = None -@@ -28,7 +26,8 @@ +@@ -28,7 +26,8 @@ class EventBus: keys filters delivery to slash-separated config paths (ancestor and descendant paths match); None subscribes to every change (wildcard). """
