feat(coding-agent): add Ctrl+Z to suspend process (#267)

* feat(tui): add isCtrlZ key detection and resetRenderState method

* feat(coding-agent): add Ctrl+Z handler to suspend process

* docs(coding-agent): add Ctrl+Z to keyboard shortcuts documentation

* feat(tui): add force parameter to requestRender
This commit is contained in:
Aliou Diallo 2025-12-21 20:19:32 +01:00 committed by GitHub
parent 55ca650a40
commit 8868d623fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 48 additions and 1 deletions

View file

@ -42,6 +42,7 @@ export {
isCtrlT,
isCtrlU,
isCtrlW,
isCtrlZ,
isDelete,
isEnd,
isEnter,

View file

@ -35,6 +35,7 @@ const CODEPOINTS = {
t: 116,
u: 117,
w: 119,
z: 122,
// Special keys
escape: 27,
@ -168,6 +169,7 @@ export const Keys = {
CTRL_T: kittySequence(CODEPOINTS.t, MODIFIERS.ctrl),
CTRL_U: kittySequence(CODEPOINTS.u, MODIFIERS.ctrl),
CTRL_W: kittySequence(CODEPOINTS.w, MODIFIERS.ctrl),
CTRL_Z: kittySequence(CODEPOINTS.z, MODIFIERS.ctrl),
// Enter combinations
SHIFT_ENTER: kittySequence(CODEPOINTS.enter, MODIFIERS.shift),
@ -223,6 +225,7 @@ const RAW = {
CTRL_T: "\x14",
CTRL_U: "\x15",
CTRL_W: "\x17",
CTRL_Z: "\x1a",
ALT_BACKSPACE: "\x1b\x7f",
SHIFT_TAB: "\x1b[Z",
} as const;
@ -322,6 +325,14 @@ export function isCtrlW(data: string): boolean {
return data === RAW.CTRL_W || data === Keys.CTRL_W || matchesKittySequence(data, CODEPOINTS.w, MODIFIERS.ctrl);
}
/**
* Check if input matches Ctrl+Z (raw byte or Kitty protocol).
* Ignores lock key bits.
*/
export function isCtrlZ(data: string): boolean {
return data === RAW.CTRL_Z || data === Keys.CTRL_Z || matchesKittySequence(data, CODEPOINTS.z, MODIFIERS.ctrl);
}
/**
* Check if input matches Alt+Backspace (legacy or Kitty protocol).
* Ignores lock key bits.

View file

@ -118,7 +118,12 @@ export class TUI extends Container {
this.terminal.stop();
}
requestRender(): void {
requestRender(force = false): void {
if (force) {
this.previousLines = [];
this.previousWidth = 0;
this.cursorRow = 0;
}
if (this.renderRequested) return;
this.renderRequested = true;
process.nextTick(() => {