fix(runtime): exit on Ctrl+C under kitty for raw-mode-only apps (#75)

Move the exitOnCtrlC guard into the always-on stdin controller (emitInput),
encoding-agnostic via parseKeypress, so Ctrl+C exits under both the legacy
\x03 byte and the kitty CSI-u form regardless of which composable holds raw
mode (useInput / useFocus / usePaste, or none). Single source of truth —
dropped from useInput. Excludes Ctrl+Shift+C; fast-paths \x03 and only parses
escape-prefixed sequences. Adds TDD PTY coverage and updates the divergence doc.

Also: stop tracking docs/superpowers/plans/2026-05-27-ink-test-parity.md —
docs/ must stay out of git (AGENTS.md); it was committed before .gitignore
covered it.
This commit is contained in:
Yunfei He
2026-05-31 00:17:21 +08:00
committed by GitHub
parent 99eb50c8ff
commit 369442d4b2
7 changed files with 105 additions and 606 deletions
+9 -6
View File
@@ -75,12 +75,15 @@ deliberate. Divergences fall into a few kinds:
### Ctrl+C exits under the kitty protocol too
- **Ink:** wires `exitOnCtrlC` only to the legacy `\x03` path, so a kitty-protocol Ctrl+C
(`\x1b[99;5u`) does **not** exit.
- **vue-tui:** `useInput` exits on `input === 'c' && key.ctrl`, gated on `exitOnCtrlC`
(default `true`), so Ctrl+C exits under **both** legacy and kitty protocols.
- **Why:** `exitOnCtrlC` reliably exiting under all protocols is the intended behavior; opt
out with `exitOnCtrlC: false`. Maintainer decision (2026-05-30): KEEP.
- **Ink:** exits only on the legacy `\x03` byte (in `App`), so a kitty-protocol Ctrl+C
(`\x1b[99;5u`) parses fine but never exits — its guard is byte-specific, not Ctrl+C-specific.
- **vue-tui:** one encoding-agnostic exit in the always-on stdin controller (`emitInput`), via
`parseKeypress` — matches Ctrl+C in both the legacy and kitty forms (but not Ctrl+Shift+C), so
it fires no matter which composable holds raw mode (`useInput` / `useFocus` / `usePaste`, or none).
- **Why:** `exitOnCtrlC` is a contract that shouldn't depend on the wire encoding; keeping the lone
exit at the single always-on layer avoids a two-place seam. Opt out with `exitOnCtrlC: false`.
Maintainer decision (2026-05-30): KEEP. Tests: `usePaste-only app exits on {legacy,kitty} Ctrl+C`
in `input-kitty.test.ts`.
## Framework-semantic divergences (Vue ≠ React)