Backspace deletes two characters instead of one in Kitty terminal
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- typescript
- Domain
- cli
Research direction
Start with apps/kimi-code/package.json and inspect the @earendil-works/pi-tui version against the reported 0.79.1 version. Update the dependency as appropriate, then run kimi in Kitty and verify that one Backspace press deletes exactly one character without breaking the existing imports.
Written by the indexing model from the issue text.
Description
Bug Description
In Kitty terminal, pressing Backspace once deletes two characters instead of one. This does NOT happen in other terminal emulators or in pi-coding-agent (which uses the same TUI library).
Environment
- Terminal: Kitty 0.32.2
- kimi-code: 0.14.2 (npm global install)
- OS: Linux
- Shell: Bash
- Node: v24.16.0
Reproduction
- Open Kitty terminal
- Run
kimi - Type some text in the input editor
- Press Backspace once
- Expected: One character deleted
- Actual: Two characters deleted
Root Cause
kimi-code ships @earendil-works/pi-tui@0.74.2, which has a buggy Kitty keyboard protocol negotiation in terminal.js. The newer pi-tui (0.79.1, used by pi-coding-agent) fixes this.
Key differences between pi-tui 0.74.2 (kimi-code) and 0.79.1 (pi-coding-agent)
1. Wrong negotiation order (most likely cause)
Old (0.74.2):
1. Send CSI ? u (query current flags)
2. Terminal responds CSI ? 0 u (flags=0, nothing pushed yet)
3. Set _kittyProtocolActive = true ← BUG: protocol not actually active yet!
4. Send CSI > 7 u (push flags 7)
5. Terminal enables flags 7
New (0.79.1):
1. Send CSI > 7 u CSI ? u CSI c (push → query → DA sentinel)
2. Terminal responds CSI ? 7 u (flags=7, already pushed)
3. Check flags !== 0 → set _kittyProtocolActive = true
The old code sets _kittyProtocolActive=true when the protocol flags are still 0 (not yet active). This creates a window where the code thinks the Kitty protocol is active but the terminal is still sending legacy-format key events (raw 0x7F for backspace). When the protocol does become active, the same keypress can be interpreted in both legacy and Kitty-protocol formats, causing double processing.
2. No negotiation buffering
The old code uses a simple regex to match the Kitty protocol response. If the response arrives split across stdin chunks, it can be missed or misinterpreted. The new code has a dedicated keyboardProtocolNegotiationBuffer with a 150ms fragment timeout.
3. No disableModifyOtherKeys()
The old code can end up with both Kitty keyboard protocol AND xterm modifyOtherKeys mode 2 active simultaneously (race condition with the 150ms fallback timeout). The new code explicitly disables modifyOtherKeys when Kitty protocol is confirmed active. Having both protocols active can cause key events to be encoded and processed twice.
4. Accepts flags=0 as "protocol active"
Old code sets _kittyProtocolActive=true on ANY Kitty response, including flags=0. New code checks flags !== 0 before enabling the protocol.
Evidence
Both apps import pi-tui as an external module (not bundled):
// kimi-code dist/main.mjs line 46:
import { ..., isKeyRelease, matchesKey, ... } from "@earendil-works/pi-tui";
Version check:
kimi-code/node_modules/@earendil-works/pi-tui: 0.74.2 ← buggy
pi-coding-agent/node_modules/@earendil-works/pi-tui: 0.79.1 ← fixed
The keys.js, stdin-buffer.js, and keybindings.js files are identical between versions — all key matching and release-event filtering logic is the same. The bug is exclusively in terminal.js protocol negotiation.
Suggested Fix
Bump the @earendil-works/pi-tui dependency from ^0.74.0 to ^0.79.0 (or latest) in apps/kimi-code/package.json.
The new version is backward-compatible — the API surface is a superset of 0.74.2 (adds MarkdownOptions, OverlayUnfocusOptions, word-navigation module, native-modifiers module). No breaking changes to the imports used by kimi-code.
Workaround
Users can manually replace the old pi-tui with a newer version:
# Replace kimi-code's pi-tui with pi-coding-agent's version
KIMI_DIR=$(npm root -g)/@moonshot-ai/kimi-code/node_modules/@earendil-works/pi-tui
PI_DIR=$(npm root -g)/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui
# Backup old version
mv "$KIMI_DIR" "${KIMI_DIR}.bak"
# Symlink to the newer version
ln -s "$PI_DIR" "$KIMI_DIR"
⚠️ This workaround will be overwritten on the next kimi-code update.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 41m
- Merged PRs (30d)
- 345
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.
More from MoonshotAI/kimi-code
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
MoonshotAI/kimi-code#3947 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
MoonshotAI/kimi-code#3836 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
MoonshotAI/kimi-code#3790 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
MoonshotAI/kimi-code#3755 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
MoonshotAI/kimi-code#3627 ·
All issues in MoonshotAI/kimi-code
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
bug clawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P2 regression
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
danielmiessler/LifeOS#2218 ·