From 878e9370bc76464673cc9d8594cbcf4457abe646 Mon Sep 17 00:00:00 2001 From: Harry Bayliss Date: Fri, 15 May 2026 19:27:42 +0100 Subject: [PATCH] Fix error flashes replacing focused pane --- CHANGELOG.md | 2 + internal/app/app.go | 11 +++++- .../error_flash_preserves_focused_pane.json | 37 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 internal/harness/scenarios/error_flash_preserves_focused_pane.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a94cba..8e85608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ loosely follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). the command field. ### Fixed +- Error/status flashes now restore the currently focused pane instead + of drawing the empty-state hint over a running agent or process. - Release workflow (`.gitea/workflows/release.yml`) now uses `mlugg/setup-zig@v2` instead of the deprecated `@v1`. v1 hard-coded the pre-0.14 tarball name (`zig-linux-x86_64-.tar.xz`), so diff --git a/internal/app/app.go b/internal/app/app.go index a589f6a..4d085a9 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2268,8 +2268,17 @@ func (st *uiState) flashError(msg string) { st.mu.Lock() st.attentionText = msg st.attentionAt = "" // shows on every focus until cleared + focusedPad := st.focusedPad + focusedID := st.focusedID st.mu.Unlock() - st.renderEmptyState() + switch { + case focusedPad != "": + st.repaintFocusedPad() + case focusedID != "": + st.repaintFocused() + default: + st.renderEmptyState() + } st.drawTabBar() st.drawSidebar() st.drawStatusLine() diff --git a/internal/harness/scenarios/error_flash_preserves_focused_pane.json b/internal/harness/scenarios/error_flash_preserves_focused_pane.json new file mode 100644 index 0000000..c2fefb3 --- /dev/null +++ b/internal/harness/scenarios/error_flash_preserves_focused_pane.json @@ -0,0 +1,37 @@ +{ + "name": "error_flash_preserves_focused_pane", + "presets": { + "processes": [ + { + "name": "steady", + "argv": ["sh", "-lc", "printf 'STEADY READY\\n'; sleep 5"] + } + ] + }, + "trust": ["steady"], + "steps": [ + { + "type": "mcp_call", + "method": "spawn_process", + "params": {"kind": "command", "preset": "steady", "name": "steady"}, + "save_as": "proc" + }, + { "type": "wait_text", "contains": "STEADY READY", "timeout_ms": 5000 }, + { "type": "send_chord", "chord": "ctrl-k" }, + { "type": "send_text", "text": "Open Settings" }, + { "type": "send_chord", "chord": "enter" }, + { "type": "send_chord", "chord": "enter" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "ctrl-n" }, + { "type": "send_chord", "chord": "enter" }, + { "type": "wait_text", "contains": "no active top-level agent to summarize", "timeout_ms": 5000 }, + { "type": "wait_text", "contains": "STEADY READY", "timeout_ms": 5000 }, + { "type": "assert_contains", "contains": "STEADY READY" }, + { "type": "assert_not_contains", "contains": "Press Ctrl-K to spawn an agent or process" } + ] +}