Skip to content

Terminal/profile startup glitches with oh-my-posh: DA escape leak, doubled prompt, slow first prompt #36

@kevmtt

Description

@kevmtt

Summary

Opening a terminal in wmux — most visibly via a quick-launch profile — produces a broken first prompt when the shell uses oh-my-posh (PowerShell + PSReadLine). Three symptoms, all rooted in how terminal queries/responses and sizing are handled across wmux's multi-process (renderer ⇄ main ⇄ pty) architecture.

Environment

  • Shell: PowerShell (pwsh) with oh-my-posh prompt + PSReadLine
  • wmux terminal: xterm.js (renderer) ⇄ Electron main ⇄ node-pty/ConPTY
  • Repro: open a quick-launch profile (even one that only sets a cwd), or any new terminal tab

Symptoms

  1. Garbled characters on the prompt. A stray escape sequence appears as if typed:

    ╰─❯ [?62;4;9;22c
    

    Typing cls to clear it yields 62;4;9;22ccls — the junk and the typed command merge into one executed line.

  2. Doubled prompt. The oh-my-posh prompt renders twice on startup.

  3. Slow / stalled first prompt. The terminal takes several seconds before the prompt appears.

Root causes

  • DA1 (Device Attributes) response leak. oh-my-posh / PSReadLine probe the terminal with a DA1 query (ESC [ c). The xterm image addon answers it with ESC [ ? 62 ; 4 ; 9 ; 22 c (62=VT220, 4=Sixel, 9, 22=ANSI color). That reply travels a slow renderer→main→pty round-trip and arrives after the prompt is drawn, so PSReadLine echoes it as typed input → the [?62;4;9;22c junk.

  • Doubled prompt = two shells per tab. React StrictMode double-mounts the terminal component in dev; the renderer's pty.has() check is async, so pty.create() could fire twice for one surfaceId, spawning a second PowerShell process that also streamed to the renderer (and leaked an orphan). Separately, spawning the PTY at the default 80×24 and then resizing it made the shell redraw the prompt.

  • Slow first prompt. The shell-integration script started the PR-polling background job with Start-Job during initStart-Job spins up a child PowerShell runspace and costs several hundred ms on the startup critical path.

Impact

Every new terminal/profile under oh-my-posh starts dirty: an executed garbage command, a duplicated prompt, and a multi-second delay. Diagnosed with an opt-in PTY I/O trace that showed the duplicate shell-init sequences and the DA round-trip timing.

Proposed fix

  • Answer DA1 in-process in PtyManager (instant) and suppress xterm's own (slow) DA1 reply.
  • Make PtyManager.create() idempotent per surfaceId; skip re-wiring a reused PTY in the IPC handler.
  • Spawn PTYs at the measured size; drop redundant same-size resizes.
  • Defer the PR Start-Job to the shell's first idle.
  • Bake quick-launch startup commands into shell init for PowerShell instead of injecting keystrokes.
  • Guard async terminal callbacks against use-after-dispose (fixes an xterm reading 'dimensions' crash).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions