Skip to content

Terminal cursor lands inside a wrapped bash prompt after widening the right panel #25419

Open

Description

@martin-ptsoft

What happened

Follow-up to #12058, which was closed after #19395. The bug still reproduces on stable v0.1.2 (desktop client and server both on 0.1.2), but the trigger is widening the panel, not narrowing it.

In the right-panel terminal, I narrow the panel until the bash prompt wraps onto a second row, then widen it again until the prompt fits on one row. After that the terminal and the shell disagree about where the line is:

  • Remote server (Ubuntu, bash 5.3.9): the cursor sits inside the prompt instead of after $. Typed characters overwrite the prompt and stay hidden until the cursor moves past the existing prompt text. In the first screenshot the caret is on the b of ...t3-8e1ddb06$, which is the column where the prompt used to wrap. In the recording, typing sdffdf shows up on screen as ...t3-8e1ddb0ffdf.
  • Local server on the same Mac, clean Homebrew bash 5.3.20 (--noprofile --norc): same as the remote case. The caret sits on the i of ...force-wrapping$, inside the prompt (second screenshot).
  • Local server on the same Mac, clean /bin/bash 3.2.57 (--noprofile --norc): the cursor sits after $ , but leftover text from the old wrapped row (s/northern-l) stays visible to the right of the cursor, so the line on screen no longer matches what readline has in its buffer (third screenshot).

It does not happen with my normal local shell (zsh).

Diagnosis

Based on the v0.1.2 source (044f07257), apps/web/src/terminal/ghostty/surface.ts:

  1. When the panel width changes, ResizeObserver calls fit() (line 833), which calls core.resize() right away. libghostty-vt then reflows the grid: the soft-wrapped prompt row joins back into one row, and the cursor moves up a row to the matching column.
  2. The PTY only hears the new size afterwards: notifyResize() waits 150ms, and since fix(web): terminal tells the shell its new width as soon as you release a resize drag #19395 onWindowPointerRelease sends it on pointer release.
  3. On SIGWINCH, bash's readline redraws using its own model of the screen, where the prompt still spans two rows (_rl_redisplay_after_sigwinch). That model no longer matches the grid Ghostty has already reflowed, so the cursor lands in the wrong place or stale cells are left behind, and later input is drawn over them.

#19395 only shortened the time between steps 1 and 2. The two sides still disagree about the screen layout, so delivering the size sooner does not fix this case.

The trigger is bash, not the remote setup: a clean local bash 5.3 reproduces the remote symptom exactly against a local server, bash 3.2 shows a variant of it, and zsh on the same machine does not reproduce it (zsh redraws its prompt differently on resize). Native Ghostty may avoid this with shell integration by clearing the prompt on resize so the shell can redraw it, but I have not checked whether the pinned libghostty-vt (9f62873bf) exposes that to the web embedder.

Steps to reproduce

  1. Desktop app 0.1.2 with a local server, or connected to a remote server, running 0.1.2.
  2. Open a thread and open a terminal in the right side panel.
  3. Start a clean bash with a long prompt:
    bash --noprofile --norc   # bash 5.x, e.g. /opt/homebrew/bin/bash on macOS
    PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
    mkdir -p /tmp/t3-triage/worktrees/northern-lights/a-long-directory-name-to-force-wrapping && cd "$_"
  4. Drag the panel divider to narrow the panel until the prompt wraps onto a second row. Release.
  5. Drag the divider to widen the panel until the prompt fits on one row again. Release.
  6. Look at the prompt line and type a few characters. The cursor is inside the prompt or there is leftover text after it, and typed input is drawn over existing text.

Version

0.1.2 (desktop client, local server, and remote server). The triage CLI was also 0.1.2.

Environment

Client: T3 Code desktop 0.1.2 on macOS 27.0 (arm64). Local server 0.1.2 on the same Mac, reproduced with Homebrew bash 5.3.20 and /bin/bash 3.2.57 (not with zsh). Remote server: T3 Code 0.1.2 on Ubuntu 26.04.1 LTS, Linux 7.0.0-34-generic x86_64, Node v24.22.1, GNU bash 5.3.9, running as the t3code.service systemd user service.

Evidence

Nothing is logged. This is a rendering problem caused by the terminal and the shell disagreeing about the screen layout.
remote: GET /.well-known/t3/environment -> "serverVersion":"0.1.2"
remote: ~/.t3/runtime/versions/0.1.2/t3 serve
v0.1.2 contains #19395 (2cde3f770): compare 2cde3f770...v0.1.2 = ahead 1822, behind 0
No commits to apps/web/src/terminal/ghostty on main since v0.1.2 touch resize.

The screen recording (remote server, bash 5.3.9) and three screenshots are attached below:

  1. Remote server, bash 5.3.9: caret on the b of ...8e1ddb06$
remote-bash-5.3-recording.mp4
  1. Local server, Homebrew bash 5.3.20: caret on the i of ...force-wrapping$
Image
  1. Local server, /bin/bash 3.2.57: leftover s/northern-l after the prompt
Image

Related issues

#12058 (closed, fixed by #19395): same symptom, but that fix covers the delay before the PTY learns the new size after narrowing. This report is the widen-after-wrap case, which still reproduces with #19395 in place. #1939 (closed) was a cursor offset at startup with Starship and is unrelated.

Fix applied or workaround

Nothing was changed on the machine. Workaround: press Ctrl+L or run clear after resizing, or close and reopen the terminal.

Filed by

Claude Code (claude-opus-5-5) via t3 triage

Activity

  1. martin-ptsoft commented on Oct 27, 2026

    @martin-ptsoft
    Author

    Above is re-tested on 0.1.3 under the same premise and is still present.

  2. martin-ptsoft commented on Oct 31, 2026

    @martin-ptsoft
    Author

    Above is re-tested on 0.1.5 under the same premise and is still present.

  3. martin-ptsoft commented on Nov 3, 2026

    @martin-ptsoft
    Author

    Above is re-tested on 0.1.6 under the same premise and is still present.

  4. skyaara commented on Nov 12, 2026

    @skyaara

    Root cause, from testing on macOS with the dev build of main. The fix is in #34786.

    1. The shells don't mark their prompt. On resize, libghostty-vt can clear the current prompt's rows so the shell redraws it cleanly. That's how Ghostty avoids this bug. It does so only when the shell marks its prompt with OSC 133 and opts in with OSC 133;A;redraw=1. For embedders the default is off (libghostty-vt: preserve shell prompts on resize by default ghostty-org/ghostty#12653). The zsh and bash that T3 Code starts send no marks, so nothing is cleared. That answers the open question above: the pinned 9f62873bf supports this, but only through those marks.
    2. A split skips the resize. A split mounts a new view that replays the history straight at the new width. libghostty-vt never sees a resize, so even a marked prompt wouldn't be cleared.

    The 150 ms delay before the PTY hears the new size isn't the cause. The terminal resizes first and the shell redraws after, the same order Ghostty enforces (ghostty-org/ghostty#14706).

    It isn't bash-only. zsh hits it when narrowing and when splitting:

    Before After the fix
    zsh, narrow the window
    zsh, split the terminal
    bash 5.3, widen the window
    bash 5.3, split the terminal

    The fix:

    • The server starts zsh and bash with small startup files. They load the user's own files, then mark the prompt the way Ghostty's shell integration does.
    • The web terminal replays history at the PTY's size, then resizes to its own.

    Limits:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions