Skip to content

fix(shell): remove queued-input bordered ghost in running-turn TUI - #216

Merged
elkaix merged 1 commit into
mainfrom
fix/queued-input-ghost
Jul 19, 2026
Merged

fix(shell): remove queued-input bordered ghost in running-turn TUI#216
elkaix merged 1 commit into
mainfrom
fix/queued-input-ghost

Conversation

@elkaix

@elkaix elkaix commented Jul 19, 2026

Copy link
Copy Markdown
Member

Summary

Pressing Enter during an active agent turn to queue a follow-up left a redundant bordered "ghost" copy of the accepted input in terminal scrollback, beside the intended teal ❯ … queued row with its ↑ to edit · ctrl-s to send immediately hint.

Root cause: the running-turn lifecycle set Application.full_screen=True mid-turn — which prompt_toolkit 3.0.52 ignores for the renderer once the session is constructed, so it never achieved its purpose — while _sync_erase_when_done() gated final-frame erasure on not full_screen. Enter therefore final-rendered the accepted buffer as a fossilized bordered card.

Changes

  • _sync_erase_when_done() now depends only on prompt mode: AGENT erases the accepted frame; SHELL keeps it in normal scrollback.
  • Removed all dynamic prompt_toolkit fullscreen toggling (_set_running_fullscreen, _previous_full_screen) and their turn-start/attach/detach calls. _turn_starting, delegate attachment, invalidation order, and pre-stream input-card gating are unchanged.
  • tui.sticky_input config key retained for backward compatibility with honest legacy wording; the composer stays inline during active turns.

Tests

  • Rewrote the fullscreen-toggle unit tests into a screen-mode-preserved running-prompt lifecycle contract: AGENT-mode erasure stays enabled even when the application/renderer full_screen fields disagree, and the lifecycle never mutates those fields.
  • Strengthened the Enter-to-queue test — exactly one queue append, one prompt invalidation, no steer/echo.
  • Added a pyte-rendered PTY regression test_mid_turn_queued_input_renders_once_and_executes_once: the queued follow-up shows its live ❯ … / ↑ to edit row and never fossilizes as a bordered accepted-input card (the ghost), and executes once in FIFO order. The guard flags the queued text only when it is wedged between a card border directly above and committed content directly below — the fossil signature — which excludes the two healthy renderings (the live queued display and the post-drain execute-echo). A/B-verified across every rendered frame: fails on the pre-fix code, passes on the fix.

Verification

  • make check-pythinker-code (ruff + format + pyright 0 errors + ty) — green.
  • make test-pythinker-code (unit + e2e including the local PTY suite) — green.
  • docs/en/release-notes/changelog.md regenerated via npm run sync.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed a TUI issue where queued follow-up input could appear as a bordered ghost or duplicate row.
    • Queued input now displays once during active turns, executes once, and restores the normal input layout afterward.
    • Preserved prompt display state while attaching and detaching running prompts.
  • Documentation

    • Updated configuration guidance and the changelog to reflect the corrected queued-input behavior.

Pressing Enter during an active agent turn left a redundant bordered copy
of the accepted input in scrollback beside the intended queued row. The
running-turn lifecycle set Application.full_screen=True mid-turn — which
prompt_toolkit 3.0.52 ignores for the renderer once the session is built,
so it never achieved its purpose — while _sync_erase_when_done gated
final-frame erasure on `not full_screen`. Enter therefore final-rendered
the accepted buffer as a fossilized bordered card.

Make accepted-prompt erasure depend only on prompt mode (AGENT erases the
accepted frame; SHELL keeps it in normal scrollback) and drop all dynamic
prompt_toolkit fullscreen toggling (_set_running_fullscreen,
_previous_full_screen). The tui.sticky_input config key is retained for
backward compatibility with honest legacy wording; the composer stays
inline during active turns.

Regression coverage: a screen-mode-preserved running-prompt lifecycle
contract, a strengthened Enter-to-queue test (one append, one invalidation,
no steer/echo), and a pyte-rendered PTY test proving the queued follow-up
renders once with its hint (never a bordered ghost) and executes once in
FIFO order.
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9b54cfd2-6ac0-4efe-9447-a21513aee59f

📥 Commits

Reviewing files that changed from the base of the PR and between f2e03b1 and 6c7574d.

⛔ Files ignored due to path filters (1)
  • docs/en/release-notes/changelog.md is excluded by !docs/**
📒 Files selected for processing (6)
  • CHANGELOG.md
  • src/pythinker_code/config.py
  • src/pythinker_code/ui/shell/prompt.py
  • tests/e2e/test_shell_pty_prompt_layout_e2e.py
  • tests/ui_and_conv/test_prompt_tips.py
  • tests/ui_and_conv/test_visualize_running_prompt.py

📝 Walkthrough

Walkthrough

Changes

Queued input lifecycle

Layer / File(s) Summary
Preserve prompt screen state
src/pythinker_code/ui/shell/prompt.py, src/pythinker_code/config.py, tests/ui_and_conv/*
CustomPromptSession no longer toggles fullscreen state during turn lifecycle transitions. Tests verify screen state preservation, erase behavior, invalidation, and default queued-input handling.
Validate queued follow-up rendering
tests/e2e/test_shell_pty_prompt_layout_e2e.py, CHANGELOG.md
PTY coverage verifies queued follow-up input renders once, executes once, avoids bordered ghost rows, and restores the idle input-card border. The changelog records the fix.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format and accurately summarizes the TUI queued-input ghost fix.
Description check ✅ Passed The description covers the summary, changes, tests, and verification; only the issue link and checklist sections are omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/queued-input-ghost

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant