Skip to content

fix(workspace): suppress stale "still running" toast when input box is hidden for non-command reasons#10742

Open
lonexreb wants to merge 3 commits into
warpdotdev:masterfrom
lonexreb:fix/9100-still-running-stale
Open

fix(workspace): suppress stale "still running" toast when input box is hidden for non-command reasons#10742
lonexreb wants to merge 3 commits into
warpdotdev:masterfrom
lonexreb:fix/9100-still-running-stale

Conversation

@lonexreb
Copy link
Copy Markdown
Contributor

Closes #9100.

Summary

The toast "A command in this session is still running." fires falsely when the user clicks something in Warp Drive (or other call sites of focus_terminal_input) and the active terminal's input box happens to be hidden for reasons unrelated to a running command. This restructures focus_terminal_input to (a) only create a new pane in the explicit "open new" branch and (b) only fire the busy toast when the active block is actually executing.

Root cause

app/src/workspace/view.rs:focus_terminal_input (lines ~15165–15237 before this change):

  1. It called active_session_view(...).unwrap_or_else(|| { add_terminal_pane(...); ...unwrap() }) to obtain a terminal view handle. Even for the RequireExisting and OpenIfNone paths, this always created a new pane when none existed.
  2. It then called self.is_input_box_visible(ctx). If false, and the fallback behavior was anything other than OpenIfNeeded, it fired the stale-command toast and returned None — leaving the user with a surprise new pane and a misleading "still running" error.
  3. TerminalView::is_input_box_visible returns false for many reasons that have nothing to do with a running command:
    • shared_session_status().is_view_pending() (app/src/terminal/view.rs:7227) — true for freshly-created panes still establishing the session.
    • is_alt_screen_active() without agent control/tag-in (view.rs:7220).
    • Active SSH remote-server choice block / remote-server setup in progress (view.rs:7261–7278).
    • Active AI block blocked on user confirmation or expanded running commands (view.rs:7280–7287).
    • Active env-var collection block, init project last step, cloud-agent pre-first-exchange, etc.

None of those are "a command is running." Mapping all of them to the still running toast is the bug reported in #9100.

Fix

app/src/workspace/view.rs

  • focus_terminal_input now resolves the existing active session without creating a new pane up front. The new pane is only added in the explicit "open new" branch at the bottom, eliminating the surprise-pane behavior for RequireExisting.
  • When there is an existing session whose input box is hidden, we delegate to a new should_show_busy_toast helper that returns true only when the active block is actually executing.

app/src/terminal/view.rs

  • New TerminalView::is_active_block_running predicate that composes the existing is_writing_or_executing_in_band_command, Block::is_executing, and Block::is_active_and_long_running predicates. We intentionally exclude blocks under agent control / tagged-in agents so the toast doesn't surface for agent flows that legitimately hide the input.

Test plan

app/src/terminal/model/block_tests.rs — new regression test test_idle_and_finished_blocks_are_not_executing that asserts the underlying predicates we now use to gate the toast (Block::is_executing, Block::is_active_and_long_running) return false for:

  • a freshly-built (never-started) block, and
  • a block that ran briefly and finished with exit 0.

These are exactly the states that previously surfaced the false toast in #9100.

Manual testing note

End-to-end repro requires building the app, which depends on crates/warpui compiling Metal shaders via Xcode's metal toolchain (xcrun metal). The Xcode toolchain is not available in this environment — only the Command Line Tools are — so cargo check -p warp and cargo test -p warp both fail at the crates/warpui/build.rs:92 shader-compile step:

thread 'main' panicked at crates/warpui/build.rs:92:5:
error compiling metal shaders to .air; xcrun: error: unable to find utility "metal", not a developer tool or in PATH

For local verification I therefore relied on:

  • Reading the surrounding state-machine code in terminal/view.rs::is_input_box_visible, pane_group/mod.rs::active_session_view, and terminal/model/block.rs to confirm the predicates compose correctly.
  • The new unit test covering the predicate-level invariant.
  • A crate-scoped cargo check -p command to confirm the shared workspace deps still build.

A reviewer with the full Xcode toolchain can finish the end-to-end repro by:

  1. Triggering any code path that hides the input box without running a command (e.g., enter vim, switch to alt-screen, or open Warp Drive on a fresh tab while shared-session is still resolving).
  2. Clicking a Warp Drive workflow / hitting a focus_terminal_input call site with RequireExisting or OpenIfNone.
  3. Confirming the "A command in this session is still running." toast no longer appears and the workflow either runs (if the session is actually free) or fails silently (RequireExisting) / opens a new pane (OpenIfNeeded) as documented on TerminalSessionFallbackBehavior.

…s hidden for non-command reasons

The toast "A command in this session is still running." was previously
gated solely on `!is_input_box_visible`. The input box is hidden for many
reasons unrelated to a running command — pending shared session, alt-screen
application, SSH choice block, AI confirmation block, freshly-created
pane in startup — and the toast fired falsely in those cases.

`focus_terminal_input` also created a new pane via `unwrap_or_else` even
in the `RequireExisting` path, then turned around and either returned None
or fired the toast, leaving a surprise pane behind.

This restructures `focus_terminal_input` so a new pane is only created
under the explicit "open new" branch, and adds an `is_active_block_running`
predicate on `TerminalView` that gates the busy toast on whether the
active block is actually executing.

Closes warpdotdev#9100.
@cla-bot cla-bot Bot added the cla-signed label May 12, 2026
@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 12, 2026
@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 12, 2026

@lonexreb

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

oz-for-oss[bot]
oz-for-oss Bot previously requested changes May 12, 2026
Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR narrows the stale "still running" toast by separating active-session lookup from pane creation and by adding a running-block predicate for the toast gate.

Concerns

  • The new running-block predicate still returns true for agent-controlled/tagged-in executing commands before the exclusion can apply.
  • The fallthrough path for unavailable existing sessions still returns the current active session without creating the new pane promised by OpenIfNeeded and the new comments.
  • No security findings were identified in the changed lines.

Verdict

Found: 0 critical, 2 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/terminal/view.rs Outdated
Comment on lines +7327 to +7330
active_block.is_executing()
|| (active_block.is_active_and_long_running()
&& !active_block.is_agent_in_control()
&& !active_block.is_agent_tagged_in())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] is_executing() makes this return true before the agent-control exclusion is evaluated, so blocked/tagged agent flows with an executing active block still show the stale busy toast. Gate the executing case with the same agent-flow exclusion.

Suggested change
active_block.is_executing()
|| (active_block.is_active_and_long_running()
&& !active_block.is_agent_in_control()
&& !active_block.is_agent_tagged_in())
if active_block.is_agent_in_control() || active_block.is_agent_tagged_in() {
return false;
}
active_block.is_executing() || active_block.is_active_and_long_running()

Comment thread app/src/workspace/view.rs Outdated
Comment on lines +15233 to +15237
if existing_terminal_view_handle.is_none() {
active_pane_group.update(ctx, |pane_group, ctx| {
pane_group.add_terminal_pane(Direction::Right, None /*chosen_shell*/, ctx);
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This guard skips pane creation whenever an existing session is unavailable, so OpenIfNeeded callers still get the hidden/busy active session back from active_session_view(ctx) instead of a new usable pane. After this fallthrough, add the replacement pane unconditionally.

Suggested change
if existing_terminal_view_handle.is_none() {
active_pane_group.update(ctx, |pane_group, ctx| {
pane_group.add_terminal_pane(Direction::Right, None /*chosen_shell*/, ctx);
});
}
active_pane_group.update(ctx, |pane_group, ctx| {
pane_group.add_terminal_pane(Direction::Right, None /*chosen_shell*/, ctx);
});

…allthrough (warpdotdev#9100)

Two issues raised by the oz-for-oss bot:

1. `is_active_block_running` previously checked the in-band-command and
   `is_executing()` short-circuits BEFORE the agent-controlled / tagged-in
   exclusion. For agent-driven long-running commands, `is_executing()`
   returns true and would fire the "still running" toast even though the
   user is intentionally interacting with the agent (and the input box is
   hidden by design). Reorder: the agent-control / tagged-in gate now runs
   FIRST and short-circuits to `false`, so executing-state checks can only
   apply to genuinely user-driven commands.

2. `focus_terminal_input` fallthrough for `OpenIfNeeded` only created a
   new pane when there was no existing session at all. When an existing
   session was present but unusable (input not visible, `should_show_busy_toast`
   suppressed by `OpenIfNeeded`), it silently returned the busy session
   instead of honoring the `OpenIfNeeded` contract. Update the condition so
   `OpenIfNeeded` always creates a new pane on fallthrough.

Tests added:
- `is_active_block_running_returns_false_for_never_started_block`
- `is_active_block_running_returns_false_for_finished_block`
- `is_active_block_running_returns_true_for_user_long_running_block`
- `is_active_block_running_returns_false_when_user_tagged_in_agent`
- `is_active_block_running_returns_false_when_agent_is_in_control`
- `focus_terminal_input_open_if_needed_creates_new_pane_when_existing_session_busy`
@lonexreb
Copy link
Copy Markdown
Contributor Author

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 12, 2026

@lonexreb

I'm re-reviewing this pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

oz-for-oss[bot]
oz-for-oss Bot previously requested changes May 12, 2026
Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR narrows the stale "still running" toast to sessions with actually running blocks and avoids eager pane creation in focus_terminal_input, with regression coverage for the new predicates and OpenIfNeeded behavior.

Concerns

  • focus_terminal_input can still return an existing hidden/unavailable session for OpenIfNone when the input is hidden for non-running reasons, letting callers operate on an input that is not focusable instead of no-oping or opening a usable pane.

Verdict

Found: 0 critical, 1 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/workspace/view.rs
// session as if it were focusable. Returning the busy session would
// reintroduce #9100 by letting callers act on a session they can't
// actually type into.
let needs_new_pane = existing_terminal_view_handle.is_none()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] OpenIfNone still reaches this fallthrough when an existing session's input is hidden for non-running reasons; because a handle exists and the fallback is not OpenIfNeeded, needs_new_pane is false and the function returns the hidden/unusable session to callers. Track that unavailable-existing-session case separately and return None or open a usable pane according to the intended contract.

When focus_terminal_input is called with OpenIfNone and an existing
session is found whose input box is hidden for non-running reasons
(alt-screen application, SSH choice block, AI confirmation block,
init-project step, cloud-agent pre-first-exchange), the prior
fallthrough returned the existing unfocusable session. Callers would
then proceed as if they had a focusable input and the user would see
no effect.

Return None in that case instead. OpenIfNone semantics: create a new
pane only when there is no existing session at all; return None when
the existing session is not usable (OpenIfNeeded handles the create
path for unusable sessions).

Add unit test focus_terminal_input_open_if_none_returns_none_when_existing_input_hidden
covering the alt-screen hidden-input case.
@lonexreb
Copy link
Copy Markdown
Contributor Author

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 12, 2026

@lonexreb

I'm re-reviewing this pull request in response to a review request.

You can view the conversation on Warp.

I reviewed this pull request and requested human review from: @warpdotdev/oss-maintainers.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@oz-for-oss oz-for-oss Bot dismissed stale reviews from themself May 12, 2026 18:26

Oz no longer requests changes for this pull request after the latest automated review.

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR updates focus_terminal_input so it no longer creates surprise panes before evaluating fallback behavior and only shows the stale-command toast when the active terminal block is actually running. It also adds predicate and workspace regression coverage for the busy-toast and pane-creation paths.

Concerns

  • No blocking correctness, security, or error-handling concerns found in the annotated diff.

Verdict

Found: 0 critical, 0 important, 0 suggestions

Approve

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@oz-for-oss oz-for-oss Bot requested review from a team and zachbai and removed request for a team May 12, 2026 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A command in this session is still running.

1 participant