[Windows] Session picker "current-terminal" resume leaves the terminal unresponsive (keys and Ctrl+C ignored)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
Environment
- OS: Windows 10/11 (ConPTY console)
- Terminal: Windows Terminal (also reproducible in other ConPTY hosts)
- jcode: v0.77.0
- Config:
keybindings.session_picker_enter = "current-terminal"
Steps to reproduce
- Run
jcode --resume(no argument) to open the session picker. - Select any session in the left pane and press Enter.
- TUI appears but is unresponsive. Typing produces no visible effect and Ctrl+C does not interrupt anything. The window must be force-closed or the stuck
jcode --resume <id>process killed manually.
jcode --resume "<session-name>" works correctly.
Root cause
crates/jcode-base/src/platform.rs::replace_process implements "exec" on Windows as:
Command::spawn()of the replacementjcode --resume <id>, then- immediate
std::process::exit(0)in the picker process.
Windows has no exec, and the spawn+exit sequence breaks the process substitution semantics that the flow relies on:
- The shell (cmd.exe) waits only for the picker process. When the picker exits, cmd.exe regains the prompt and begins reading console input again.
- The replacement child keeps running attached to the same console, and both cmd.exe and the child now block on the shared console input buffer.
Keystrokes are consumed by an arbitrary one of the two readers. - The child's TUI enables raw mode (no ENABLE_PROCESSED_INPUT, no echo) for the console; these modes are console-global, so there is no echo and Ctrl+C no longer generates a break signal.
- Result: the terminal appears frozen and ignores all input, including Ctrl+C.
Evidence from a live repro: the replacement child processes boot fully (TUI_TERMINAL_MODES initialized, first frame rendered, session history restored, MCP servers connected) and then log zero activity for the rest of their lifetime, i.e. input never reaches them.
Suggested fix
Preserve the wait chain on Windows so the invoking shell does not regain the console while the replacement client runs:
- Simplest: in the picker's current-terminal path, after spawning the child, the parent should
child.wait()for the child to exit instead of exiting immediately (possibly also re-attaching console control handlers). This keeps cmd.exe blocked and the console input single-reader. - Alternatively, use the existing terminal-mode handoff machinery (
TUI_TERMINAL_MODEShandoff flags) together with the wait, so the child can skip re-entering raw/alt-screen state it already owns. - Or route "current-terminal" to the "new-terminal" behavior on Windows.
Workaround for users
- Use
jcode --resume "<session-name>"directly, or - Set
keybindings.session_picker_enter = "new-terminal"in config.toml.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in crates/jcode-base/src/platform.rs at replace_process and trace the current-terminal session-picker path on Windows. Reproduce with jcode --resume and the current-terminal binding, then verify the replacement client keeps the shell blocked and accepts keyboard input and Ctrl+C without leaving the terminal unresponsive.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100