Skip to content

bug: Shell escape (!) in --tui mode does not yield terminal stdin to interactive subprocesses #3694

@ElBlackwood

Description

@ElBlackwood

Checks

Operating system

Ubuntu 24.04 LTS on WSL2 (kernel 6.6.87.2-microsoft-standard-WSL2)

Expected behaviour

When running an interactive command via the ! shell escape in --tui mode (e.g. !my-script where the script uses read -r to wait for user input), the CLI
should temporarily:

  1. Save the TUI terminal state
  2. Restore the terminal to cooked mode
  3. Yield stdin to the child process
  4. Re-enter TUI/raw mode when the subprocess exits
    This is the standard pattern used by other TUI applications that support shell escapes (vim :!cmd, less !cmd, htop, etc.).
    The non-TUI kiro-cli chat mode handles ! commands correctly — this is specific to --tui.

Actual behaviour

In --tui mode, the TUI retains raw terminal control and does not yield stdin to the subprocess. This causes two failure modes depending on how the script reads
input:

  1. read -r (from stdin): Gets immediate EOF — the script doesn't wait for input and exits instantly
  2. read -r </dev/tty (from terminal device): Hangs indefinitely — /dev/tty is accessible but the TUI's raw mode input loop is consuming all keypresses.
    Enter and Ctrl+C never reach the subprocess. The only recovery is force-killing kiro-cli from another terminal.

Steps to reproduce

  1. Create a minimal interactive script:
#!/usr/bin/env bash
echo "Press Enter to continue..." >&2
read -r
echo "Done!" >&2

Save as ~/bin/test-interactive, chmod +x.
2. Start kiro-cli in TUI mode:

kiro-cli chat --tui
  1. Run the script via shell escape:
> !test-interactive

Result: Script either exits instantly (stdin EOF) or hangs forever (/dev/tty blocked by TUI). Terminal becomes unresponsive to Ctrl+C.
4. Compare with non-TUI mode:

kiro-cli chat
> !test-interactive

Result: Works correctly — waits for Enter, then prints "Done!".

Real-world impact

A voice recording script that uses read -r to wait for Enter (to stop recording) cannot be used via ! in TUI mode. The recording either captures nothing
(immediate exit) or requires force-killing the process.

Additional context

  • PR feat(tools): execute_bash uses PTY for shell integrations #1340 (feat(tools): execute_bash uses PTY for shell integrations) addressed a related issue for the execute_bash tool but was closed without merging.
  • The fix pattern is well-established: save terminal state → tcsetattr to restore cooked mode → fork/exec with inherited stdin/stdout/stderr → waitpid
    restore TUI raw mode. This is how ncurses endwin()/refresh() and crossterm disable_raw_mode()/enable_raw_mode() handle it.

Environment

[q-details]
version = "1.28.1"
hash = "fc92565d6f51c1708e92500b2b2bcc4a424f5705"
date = "2026-03-21T05:18:11.590914Z"
variant = "minimal"
[system-info]
chip = "Intel(R) Core(TM) Ultra 7 265H"
total-cores = 16
memory = "15.35 GB"
[system-info.os.linux]
kernel_version = "6.6.87.2-microsoft-standard-WSL2"
id = "ubuntu"
name = "Ubuntu"
pretty_name = "Ubuntu 24.04 LTS"
version_id = "24.04"
[environment]
os = "Linux"
shell-path = "/bin/bash"
in-wsl = true

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