- Fixed markdown H1 headings ending with inline code from leaking underline styling into trailing line padding
- Fixed slash-command argument autocomplete to await async
getArgumentCompletions()results and ignore invalid return values, preventing crashes when extension commands provide asynchronous completions (#2719) - Fixed non-capturing overlay padding from inflating scrollback and corrupting the viewport on terminal widen (#2758 by @dotBeeps)
- Fixed TUI cell size response handling to consume only exact
CSI 6 ; height ; width treplies, so bareEscapeis no longer swallowed while waiting for terminal image metadata (#2661) - Fixed Kitty keyboard protocol keypad functional keys to normalize to logical digits, symbols, and navigation keys, so numpad input in terminals such as iTerm2 no longer inserts Private Use Area gibberish or gets ignored (#2650)
- Added support for
PI_TUI_WRITE_LOGdirectory paths, creating a unique log file (tui-<timestamp>-<pid>.log) per instance for easier debugging of multiple pi sessions (#2508 by @mrexodia)
- Fixed blockquote text color breaking after inline links (and other inline elements) due to missing style restoration prefix
- Fixed slash-command Tab completion from immediately chaining into argument autocomplete after completing the command name, restoring flows like
/modelthat submit into a selector dialog (#2577) - Fixed stale content and incorrect viewport tracking after TUI content shrinks or transient components inflate the working area (#2126 by @Perlence)
- Fixed
@autocomplete to debounce editor-triggered searches, cancel in-flightfdlookups cleanly, and keep suggestions visible while results refresh (#1278)
- Fixed
truncateToWidth()to stream truncation for very large strings, keep contiguous prefixes, and always terminate truncated SGR styling safely (#2447) - Fixed markdown heading styling being lost after inline code spans within headings
- Fixed shared keybinding resolution to stop user overrides from evicting unrelated default shortcuts such as selector confirm and editor cursor keys (#2455)
- Fixed Termux software keyboard height changes from forcing full-screen redraws and replaying TUI history on every toggle (#2467)
- Replaced the editor-only keybinding store with a single global keybindings manager in
@mariozechner/pi-tui. TUI keybinding ids are now namespaced:cursorUp->tui.editor.cursorUp,cursorDown->tui.editor.cursorDown,cursorLeft->tui.editor.cursorLeft,cursorRight->tui.editor.cursorRight,cursorWordLeft->tui.editor.cursorWordLeft,cursorWordRight->tui.editor.cursorWordRight,cursorLineStart->tui.editor.cursorLineStart,cursorLineEnd->tui.editor.cursorLineEnd,jumpForward->tui.editor.jumpForward,jumpBackward->tui.editor.jumpBackward,pageUp->tui.editor.pageUp,pageDown->tui.editor.pageDown,deleteCharBackward->tui.editor.deleteCharBackward,deleteCharForward->tui.editor.deleteCharForward,deleteWordBackward->tui.editor.deleteWordBackward,deleteWordForward->tui.editor.deleteWordForward,deleteToLineStart->tui.editor.deleteToLineStart,deleteToLineEnd->tui.editor.deleteToLineEnd,yank->tui.editor.yank,yankPop->tui.editor.yankPop,undo->tui.editor.undo,newLine->tui.input.newLine,submit->tui.input.submit,tab->tui.input.tab,copy->tui.input.copy,selectUp->tui.select.up,selectDown->tui.select.down,selectPageUp->tui.select.pageUp,selectPageDown->tui.select.pageDown,selectConfirm->tui.select.confirm,selectCancel->tui.select.cancel.keybindings.jsonstays backward compatible because each keybinding definition maps the new internal id back to the existing public config key. Apps extendinterface Keybindingsvia declaration merging, create one manager with both TUI and app definitions, then install it withsetKeybindings(...)(#2391)
- Fixed user-defined keybindings to shadow conflicting default bindings across the shared registry, so app-level defaults no longer stay active when the same key is explicitly reassigned (#2391)
- Fixed tmux xterm
modifyOtherKeysmatching forBackspace,Escape, andSpace, and resolved raw\x08backspace ambiguity by treating Windows Terminal sessions differently from legacy terminals (#2293)
- Added configurable
SelectListprimary column sizing viaSelectListLayoutOptions, including custom primary-label truncation hooks (#2154 by @markusylisiurunen)
- Fixed stale scrollback remaining after full-screen redraws such as session switches by clearing the screen before wiping scrollback (#2155 by @Perlence)
- Fixed trailing blank lines after markdown block elements when they are followed immediately by the next block or end of document (#2152 by @markusylisiurunen)
- Fixed Windows shell and path handling in autocomplete to properly handle drive letters and mixed path separators
- Fixed editor paste to preserve literal content instead of normalizing newlines, preventing content corruption for text with embedded escape sequences (#2064)
- Fixed tab completion to preserve
./prefix when completing relative paths (#2087) - Fixed
ctrl+backspacebeing indistinguishable from plainbackspaceon Windows Terminal.0x08is now recognized asctrl+backspaceinstead ofbackspace, makingctrl+backspacebindable on terminals where it produces a distinct byte (#2139)
- Added paste marker atomic segment handling in editor, treating paste markers as indivisible units during word wrapping and cursor navigation (#2111 by @haoqixu)
- Fixed
Inputhorizontal scrolling for wide Unicode text (CJK, fullwidth characters) to use visual column width and strict slice boundaries, preventing rendered line overflow and TUI crashes (#1982) - Fixed xterm
modifyOtherKeyshandling forTabinmatchesKey(), restoringshift+taband other modified Tab bindings in tmux whenextended-keys-formatis left at the defaultxterm - Fixed editor scroll indicator rendering crash in narrow terminal widths (#2103 by @haoqixu)
- Fixed tab characters in editor
setText()and input paths not being normalized to spaces (#2027 by @haoqixu) - Fixed
wordWrapLineoverflow when wide characters (CJK, fullwidth) fall exactly at the wrap boundary (#2082 by @haoqixu) - Fixed tab characters in
Inputpaste not being normalized to spaces (#1975 by @haoqixu)
- Added
treeFoldOrUpandtreeUnfoldOrDowneditor actions with default bindings forCtrl+←/Ctrl+→andAlt+←/Alt+→(#1724 by @Perlence) - Added digit keys (
0-9) to the keybinding system, including Kitty CSI-u and xtermmodifyOtherKeyssupport for bindings likectrl+1(#1905)
- Fixed autocomplete selection ignoring typed text: highlight now follows the first prefix match as the user types, and exact matches are always selected on Enter (#1931 by @aliou)
- Fixed xterm
modifyOtherKeysparsing inmatchesKey()andparseKey(), restoring Ctrl-based keybindings and modified Enter keys in tmux whenextended-keys-formatis left at the defaultxterm(#1872) - Fixed slash-command Tab completion to immediately open argument completions when available (#1481 by @barapa)
- Added non-capturing overlays via
OverlayOptions.nonCapturingand newOverlayHandlemethods:focus(),unfocus(), andisFocused()for programmatic overlay focus control (#1916 by @nicobailon)
- Overlay compositing order now uses focus order so focused overlays render on top while preserving stack semantics for show/hide behavior (#1916 by @nicobailon)
- Fixed automatic focus restoration to skip non-capturing overlays and fixed
hideOverlay()to only reassign focus when the popped overlay had focus (#1916 by @nicobailon)
- Added xterm modifyOtherKeys mode 2 fallback when Kitty keyboard protocol is not available, enabling modified enter keys (Shift+Enter, Ctrl+Enter) inside tmux (#1872)
- Exported
decodeKittyPrintable()fromkeys.tsfor decoding Kitty CSI-u sequences into printable characters
- Fixed
Inputcomponent not accepting typed characters when Kitty keyboard protocol is active (e.g., VS Code 1.110+), causing model selector filter to ignore keystrokes (#1857) - Fixed editor/footer visibility drift during terminal resize by forcing full redraws when terminal width or height changes (#1844 by @ghoulr).
- Fixed markdown blockquote rendering to isolate blockquote styling from default text style, preventing style leakage.
- Fixed TUI width calculation for regional indicator symbols (e.g. partial flag sequences like
🇨during streaming) to prevent wrap drift and stale character artifacts in differential rendering. - Fixed Kitty CSI-u handling to ignore unsupported modifiers so modifier-only events do not insert stray printable characters (#1807)
- Fixed single-line paste performance by inserting pasted text atomically instead of character-by-character, preventing repeated
@autocomplete scans during paste (#1812) - Fixed
visibleWidth()to ignore generic OSC escape sequences (including OSC 133 semantic prompt markers), preventing width drift when terminals emit semantic zone markers (#1805) - Fixed markdown blockquotes dropping nested list content by rendering blockquote children as block-level tokens (#1787)
- Fixed Windows VT input initialization in ESM by loading
koffiviacreateRequire, restoring VT input mode while keepingkoffiexternalized from compiled binaries (#1627 by @kaste)
- Changed koffi import from top-level to dynamic require in
enableWindowsVTInput()to prevent bun from embedding all 18 platform.nodefiles (~74MB) into every compiled binary. Koffi is only needed on Windows.
- Added terminal input listeners in
TUI(addInputListenerandremoveInputListener) to let callers intercept, transform, or consume raw input before component handling.
- Fixed
@autocomplete fuzzy matching to score against path segments and prefixes, reducing irrelevant matches for nested paths (#1423)
- Added
pasteToEditortoEditorComponentAPI for programmatic paste support (#1351 by @kaofelix) - Added kill ring (ctrl+k/ctrl+y/alt+y) and undo (ctrl+z) support to the Input component (#1373 by @Perlence)
- Slash command menu now triggers on the first line even when other lines have content, allowing commands to be prepended to existing text (#1227 by @aliou)
- Fixed
/settingscrashing in narrow terminals by handling small widths in the settings list (#1246 by @haoqixu)
- Added
Terminal.drainInput()to drain stdin before exit (prevents Kitty key release events leaking over slow SSH)
- Fixed Kitty key release events leaking to parent shell over slow SSH connections by draining stdin for up to 1s (#1204)
- Fixed legacy newline handling in the editor to preserve previous newline behavior
- Fixed @ autocomplete to include hidden paths
- Fixed submit fallback to honor configured keybindings
- Added
PI_DEBUG_REDRAW=1env var for debugging full redraws (logs triggers to~/.pi/agent/pi-debug.log)
- Terminal height changes no longer trigger full redraws, reducing flicker on resize
clearOnShrinknow defaults tofalse(usePI_CLEAR_ON_SHRINK=1orsetClearOnShrink(true)to enable)
-
Fixed emoji cursor positioning in Input component (#1183 by @haoqixu)
-
Fixed unnecessary full redraws when appending many lines after content had previously shrunk (viewport check now uses actual previous content size instead of stale maximum)
-
Fixed Ctrl+D exit closing the parent SSH session due to stdin buffer race condition (#1185)
- Added sticky column tracking for vertical cursor navigation so the editor restores the preferred column when moving across short lines. (#1120 by @Perlence)
- Fixed Kitty keyboard protocol base layout fallback so non-QWERTY layouts do not trigger wrong shortcuts (#1096 by @rytswd)
- Optimized
isImageLine()withstartsWithshort-circuit for faster image line detection
- Fixed empty rows appearing below footer when content shrinks (e.g., closing
/tree, clearing multi-line editor) (#1095 by @marckrenn) - Fixed terminal cursor remaining hidden after exiting TUI via
stop()when a render was pending (#1099 by @haoqixu)
- Fixed
isImageLine()to check for image escape sequences anywhere in a line, not just at the start. This prevents TUI crashes when rendering lines containing image data. (#1091 by @zedrdave)
- Added Ctrl+B and Ctrl+F as alternative keybindings for cursor word left/right navigation (#1053 by @ninlds)
- Added character jump navigation: Ctrl+] jumps forward to next character, Ctrl+Alt+] jumps backward (#1074 by @Perlence)
- Editor now jumps to line start when pressing Up at first visual line, and line end when pressing Down at last visual line (#1050 by @4h9fbZ)
- Fixed autocomplete for paths with spaces by supporting quoted path tokens (#1077)
- Fixed quoted path completions to avoid duplicating closing quotes during autocomplete (#1077)
- Added
autocompleteMaxVisibleoption toEditorOptionswith getter/setter methods for configurable autocomplete dropdown height (#972 by @masonc15) - Added
alt+bandalt+fas alternative keybindings for word navigation (cursorWordLeft,cursorWordRight) andctrl+dfordeleteCharForward(#1043 by @jasonish) - Editor auto-applies single suggestion when force file autocomplete triggers with exactly one match (#993 by @Perlence)
- Improved
extractCursorPositionperformance: scans lines in reverse order, early-outs when cursor is above viewport, and limits scan to bottom terminal height (#1004 by @can1357) - Autocomplete improvements: better handling of partial matches and edge cases (#1024 by @Perlence)
- Fixed backslash input buffering causing delayed character display in editor and input components (#1037 by @Perlence)
- Fixed markdown table rendering with proper row dividers and minimum column width (#997 by @tmustier)
- Added
fullRedrawsreadonly property to TUI class for tracking full screen redraws - Added
PI_TUI_WRITE_LOGenvironment variable to capture raw ANSI output for debugging
- Fixed appended lines not being committed to scrollback, causing earlier content to be overwritten when viewport fills (#954)
- Slash command menu now only triggers when the editor input is otherwise empty (#904)
- Center-anchored overlays now stay vertically centered when resizing the terminal taller after a shrink (#950 by @nicobailon)
- Fixed editor multi-line insertion handling and lastAction tracking (#945 by @Perlence)
- Fixed editor word wrapping to reserve a cursor column (#934 by @Perlence)
- Fixed editor word wrapping to use single-pass backtracking for whitespace handling (#924 by @Perlence)
- Fixed Kitty image ID allocation and cleanup to prevent image ID collisions between modules
codeBlockIndentproperty onMarkdownThemeto customize code block content indentation (default: 2 spaces) (#855 by @terrorobe)- Added Alt+Delete as hotkey for delete word forwards (#878 by @Perlence)
- Fuzzy matching now scores consecutive matches higher and penalizes gaps more heavily for better relevance (#860 by @mitsuhiko)
- Autolinked emails no longer display redundant
(mailto:...)suffix in markdown output (#888 by @terrorobe) - Fixed viewport tracking and cursor positioning for overlays and content shrink scenarios
- Autocomplete now allows searches with
/characters (e.g.,folder1/folder2) (#882 by @richardgill) - Directory completions for
@file attachments no longer add trailing space, allowing continued autocomplete into subdirectories
- Added undo support to Editor with Ctrl+- hotkey. Undo coalesces consecutive word characters into one unit (fish-style). (#831 by @Perlence)
- Added legacy terminal support for Ctrl+symbol keys (Ctrl+, Ctrl+], Ctrl+-) and their Ctrl+Alt variants. (#831 by @Perlence)
- Added
showHardwareCursorgetter and setter to control cursor visibility while keeping IME positioning active. (#800 by @ghoulr) - Added Emacs-style kill ring editing with yank and yank-pop keybindings. (#810 by @Perlence)
- Added legacy Alt+letter handling and Alt+D delete word forward support in the editor keymap. (#810 by @Perlence)
EditorOptionswith optionalpaddingXfor horizontal content padding, plusgetPaddingX()/setPaddingX()methods (#791 by @ferologics)
- Hardware cursor is now disabled by default for better terminal compatibility. Set
PI_HARDWARE_CURSOR=1to enable (replacesPI_NO_HARDWARE_CURSOR=1which disabled it).
- Decode Kitty CSI-u printable sequences in the editor so shifted symbol keys (e.g.,
@,?) work in terminals that enable Kitty keyboard protocol (#779 by @iamd3vil)
Editorconstructor now requiresTUIas first parameter:new Editor(tui, theme). This enables automatic vertical scrolling when content exceeds terminal height. (#732)
- Hardware cursor positioning for IME support in
EditorandInputcomponents. The terminal cursor now follows the text cursor position, enabling proper IME candidate window placement for CJK input. (#719) Focusableinterface for components that need hardware cursor positioning. Implementfocused: booleanand emitCURSOR_MARKERin render output when focused.CURSOR_MARKERconstant andisFocusable()type guard exported from the package- Editor now supports Page Up/Down keys (Fn+Up/Down on MacBook) for scrolling through large content (#732)
- Expanded keymap coverage for terminal compatibility: added support for Home/End keys in tmux, additional modifier combinations, and improved key sequence parsing (#752 by @richardgill)
- Editor no longer corrupts terminal display when text exceeds screen height. Content now scrolls vertically with indicators showing lines above/below the viewport. Max height is 30% of terminal (minimum 5 lines). (#732)
visibleWidth()andextractAnsiCode()now handle APC escape sequences (ESC _ ... BEL), fixing width calculation and string slicing for strings containing cursor markers- SelectList now handles multi-line descriptions by replacing newlines with spaces (#728 by @richardgill)
- Keyboard shortcuts (Ctrl+C, Ctrl+D, etc.) now work on non-Latin keyboard layouts (Russian, Ukrainian, Bulgarian, etc.) in terminals supporting Kitty keyboard protocol with alternate key reporting (#718 by @dannote)
OverlayOptionsAPI for overlay positioning and sizing with CSS-like values:width,maxHeight,row,colaccept numbers (absolute) or percentage strings (e.g.,"50%"). Also supportsminWidth,anchor,offsetX,offsetY,margin. (#667 by @nicobailon)OverlayOptions.visiblecallback for responsive overlays - receives terminal dimensions, return false to hide (#667 by @nicobailon)showOverlay()now returnsOverlayHandlewithhide(),setHidden(boolean),isHidden()for programmatic visibility control (#667 by @nicobailon)- New exported types:
OverlayAnchor,OverlayHandle,OverlayMargin,OverlayOptions,SizeValue(#667 by @nicobailon) truncateToWidth()now accepts optionalpadparameter to pad result with spaces to exactlymaxWidth(#667 by @nicobailon)
- Overlay compositing crash when rendered lines exceed terminal width due to complex ANSI/OSC sequences (e.g., hyperlinks in subagent output) (#667 by @nicobailon)
SettingsListOptionswithenableSearchfor fuzzy filtering inSettingsList(#643 by @ninlds)pageUpandpageDownkey support withselectPageUp/selectPageDowneditor actions (#662 by @aliou)
- Numbered list items showing "1." for all items when code blocks break list continuity (#660 by @ogulcancelik)
fuzzyFilter()andfuzzyMatch()utilities for fuzzy text matching- Slash command autocomplete now uses fuzzy matching instead of prefix matching
- Cursor now moves to end of content on exit, preventing status line from being overwritten (#629 by @tallshort)
- Reset ANSI styles after each rendered line to prevent style leakage
- Reduced flicker by only re-rendering changed lines (#617 by @ogulcancelik)
- Cursor position tracking when content shrinks with unchanged remaining lines
- TUI renders with wrong dimensions after suspend/resume if terminal was resized while suspended (#599)
- Pasted content containing Kitty key release patterns (e.g.,
:3Fin MAC addresses) was incorrectly filtered out (#623 by @ogulcancelik)
- Experimental: Overlay compositing for
ctx.ui.custom()with{ overlay: true }option (#558 by @nicobailon)
EditorComponentinterface for custom editor implementationsStdinBufferclass to split batched stdin into individual sequences (adapted from OpenTUI, MIT license)
- Key presses no longer dropped when batched with other events over SSH (#538)
Component.wantsKeyReleaseproperty to opt-in to key release events (default false)
- TUI now filters out key release events by default, preventing double-processing of keys in editors and other components
matchesKey()now correctly matches Kitty protocol sequences for unmodified letter keys (needed for key release events)
- Kitty keyboard protocol flag 2 support for key release events. New exports:
isKeyRelease(data),isKeyRepeat(data),KeyEventTypetype. Terminals supporting Kitty protocol (Kitty, Ghostty, WezTerm) now send proper key-up events.
- Crash when pasting text with trailing whitespace exceeding terminal width through Markdown rendering (#457 by @robinwander)
- Symbol key support in keybinding system:
SymbolKeytype with 32 symbol keys,Keyconstants (e.g.,Key.backtick,Key.comma), updatedmatchesKey()andparseKey()to handle symbol input (#450 by @kaofelix)
Editor.getExpandedText()method that returns text with paste markers expanded to their actual content (#444 by @aliou)
- Key detection functions removed: All
isXxx()key detection functions (isEnter(),isEscape(),isCtrlC(), etc.) have been removed. UsematchesKey(data, keyId)instead (e.g.,matchesKey(data, "enter"),matchesKey(data, "ctrl+c")). This affects hooks and custom tools that usectx.ui.custom()with keyboard input handling. (#405)
Editor.insertTextAtCursor(text)method for programmatic text insertion (#419)EditorKeybindingsManagerfor configurable editor keybindings. Components now usematchesKey()and keybindings manager instead of individualisXxx()functions. (#405 by @hjanuschka)
- Key detection refactored: consolidated
is*()functions into genericmatchesKey(data, keyId)function that accepts key identifiers like"ctrl+c","shift+enter","alt+left", etc.
- Slash command autocomplete now triggers for commands starting with
.,-, or_(e.g.,/.land,/-foo) (#422)
- Editor component now uses word wrapping instead of character-level wrapping for better readability (#382 by @nickseelert)
- Shift+Space, Shift+Backspace, and Shift+Delete now work correctly in Kitty-protocol terminals (Kitty, WezTerm, etc.) instead of being silently ignored (#411 by @nathyong)
visibleWidth()now strips OSC 8 hyperlink sequences, fixing text wrapping for clickable links (#396 by @Cursivez)
isShiftCtrlO()key detection function for Shift+Ctrl+O (Kitty protocol)isShiftCtrlD()key detection function for Shift+Ctrl+D (Kitty protocol)TUI.onDebugcallback for global debug key handling (Shift+Ctrl+D)wrapTextWithAnsi()utility now exported (wraps text to width, preserving ANSI codes)
- README.md completely rewritten with accurate component documentation, theme interfaces, and examples
visibleWidth()reimplemented with grapheme-based width calculation, 10x faster on Bun and ~15% faster on Node (#369 by @nathyong)
- Markdown component now renders HTML tags as plain text instead of silently dropping them (#359)
- Crash in
visibleWidth()and grapheme iteration when encountering undefined code points (#372 by @HACKE-RC) - ZWJ emoji sequences (rainbow flag, family, etc.) now render with correct width instead of being split into multiple characters (#369 by @nathyong)
- Auto-space before pasted file paths: When pasting a file path (starting with
/,~, or.) and the cursor is after a word character, a space is automatically prepended for better readability. Useful when dragging screenshots from macOS. (#307 by @mitsuhiko) - Word navigation for Input component: Added Ctrl+Left/Right and Alt+Left/Right support for word-by-word cursor movement. (#306 by @kim0)
- Full Unicode input: Input component now accepts Unicode characters beyond ASCII. (#306 by @kim0)