FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Input completely dead in Herdr pane on Windows: TUI renders but never receives keystrokes · Issue #982 · CommandCodeAI/command-code · GitHub

Repository navigation

Input completely dead in Herdr pane on Windows: TUI renders but never receives keystrokes #982

Description

Summary

Command Code renders its full TUI correctly inside a Herdr pane on Windows, but the input box never responds, no characters appear, esc does not dismiss the capacity banner, and ? does not open the shortcuts overlay. The identical build works normally in a plain Windows Terminal tab, so the failure is specific to running inside Herdr's ConPTY.

Herdr is a terminal multiplexer that sits between the outer terminal and the process. I isolated the fault to that boundary: bytes do reach the pane, a minimal Ink 7 useInput app in the same pane works fine, and command-code's own stdin ends
up correctly armed for raw-mode input, yet it never dispatches the keys it receives. I suspect command-code's startup terminal-capability probes, which take exclusive control of process.stdin and unshift leftover reply bytes back into the stream, are being desynchronized by Herdr answering the Kitty keyboard query itself.

Expected Behavior

Typing in the prompt inside a Herdr pane should insert characters into the input box and allow submitting, the same as in any other terminal.

Actual Behavior

The TUI paints completely and correctly (logo, model line, prompt, hint footer), but the process never acts on keyboard input:

  • Typing letters, digits, esc, ?, and ctrl+c produces no visible change.
  • The prompt stays on the ❯ Ask your question... placeholder indefinitely.
  • The "◼ Space Bunny Alpha is free ... · esc to dismiss" banner never goes away.
  • Output is unaffected — the UI redraws and the model/API connection works; only input is dead.

Deterministic, not intermittent: I tested continuously for 120 seconds and no keystroke was ever processed. I initially thought it was flaky, but that turned out to be a separate plain-node process in another pane echoing input, not Command Code responding.

What I verified about the boundary:

  1. Keys DO reach the pane. A PowerShell Host.UI.RawUI.ReadKey watcher running in
    the same pane captured every injected keystroke.
  2. A minimal Ink 7.1.0 app using useInput, launched in the same pane, works
    correctly and echoes typed characters.
  3. Raw mode + on('data'), readline keypress events with setEncoding('utf8'),
    and Ink's own addListener('readable') model each all receive keys when tested
    standalone in a Herdr pane.
  4. Input keeps working both before and after a pane enters the alternate screen
    (ESC[?1049h), so alternate-screen handling is not the cause.
  5. Herdr answers the Kitty keyboard protocol query: command-code emits
    CSI ? u and receives ESC[?0u back. When I reproduced command-code's probe
    sequence in a working Ink app, that reply surfaced as literal typed text
    (TYPED: [[?0u12345]), which suggests reply bytes are being re-injected into
    the input stream.
  6. Instrumenting process.stdin during a real command-code launch shows a healthy
    steady state — isRaw=true, readable=1, dataListeners=1 — yet no dispatch.
  7. HERDR_WINDOWS_CONPTY=system does not change the behavior.

The suspected code path is the startup probe in dist/cli.mjs, which forces raw
mode, attaches its own data listener, writes the Kitty query, then on settle
calls stdin.off('data', c), stdin.unshift(leftover), and
if (!wasRaw) stdin.setRawMode(false). Seeding and unsetting process.stdin like
this is fragile under a multiplexer that responds to terminal capability queries
itself.

Steps to reproduce the issue

  1. Install Command Code on Windows (Node 22+; I used Node 24.18.0).
  2. Install Herdr and launch it (herdr).
  3. Open a new workspace/pane in Herdr.
  4. Run command-code (on Windows the alias is cmdc, not cmd).
  5. Wait for the TUI to finish painting.
  6. Type any character.
  7. Observe: nothing is inserted. The prompt keeps showing the "Ask your question..." placeholder, and the capacity banner will not dismiss with esc.
  8. Control: run command-code in a plain Windows Terminal tab. Typing works there.

Command Code Version

1.74.1

Operating System

Windows

Terminal/IDE

Unknown

Shell

cmd.exe

Session file (optional)

No response

Fix prompt (optional)

No response

Additional context

No response

Activity

  1. added theissue type on Oct 3, 2026
  2. wjsxhz commented on Oct 4, 2026

    I have same problem. I used Opencode+Space Bunny checked the issue. AI gave below explanation:

    Conclusion:
    the console is left in cooked (line-input + echo) mode, so every keystroke is swallowed by conhost's line buffer
    I reproduced this locally in a ConPTY (the same Windows console host Windows Terminal uses) and traced it to the root cause. It is not a focus problem and not a TTY problem.

    Evidence
    Running cmd -t inside a PTY and typing into it, capturing the raw output stream:

    type "1" (NO Enter)

    5.01s CHUNK "\u001b[?25l\r\n1\u001b[?25h" <- conhost echo, NOT a TUI repaint

    now Enter

    8.01s CHUNK "\u001b[?25l\u001b[?25h"
    Control: a minimal Ink 7.1.0 app in the same PTY produces an actual Ink repaint when you type (keys=1 buf=[abc] isRaw=true) and no echo at all. That is what a correctly raw-mode Ink TUI looks like. Command Code only ever gets the conhost echo back.
    process.stdin.isRaw reports true (Node believes raw mode is on), but the console is actually still in cooked mode. Consequences:

    • Arrow keys and Esc do nothing (they are inert under cooked-mode line editing).
    • Characters accumulate in conhost's line buffer and are only delivered when you press Enter.
    • This is exactly why the trust prompt "does nothing when you press 1" — the 1 never leaves conhost.

    Root cause: the startup terminal probes break stdin
    In dist\cli.mjs, interactiveMode runs two terminal-capability probes back to back, both of which hijack process.stdin directly:
    Function What it does
    queryTerminalBackground() Writes OSC 11 (ESC]11;?BEL) to stdout to query the terminal background color. Does setRawMode(true) → resume() → on('data'), then on timeout pause() / setRawMode(false) / unshift()
    queryKittyKeyboardSupport() Writes CSI ? u to probe Kitty keyboard protocol support, same pattern
    startEarlyInputCapture() Attaches a persistent data listener to buffer keystrokes that arrive early
    On Windows, after this setRawMode / resume / pause sequence, the console can never enter raw mode again. I verified that once broken it cannot be repaired from outside the process: si.setRawMode(true), si.resume(), si.read(0), a setRawMode(false)→true toggle, and attaching a data listener to force flowing mode — all six variants failed. Each was tested in a real PTY with actual detection of whether Ink repaints.

    Workaround (verified)
    Both probes are gated on env.TERM !== 'dumb', so TERM=dumb skips them entirely:
    $env:TERM="dumb"

    ...
    cmd

  3. naymurdev commented on Oct 5, 2026

    Lemme have a look at this issue

  4. self-assigned this
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL