@linxiraos/pi-tui 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +1 -2268
  2. package/LICENSE +23 -0
  3. package/README.md +1 -1
  4. package/package.json +68 -69
  5. package/src/autocomplete.ts +147 -61
  6. package/src/components/composer/borderless.ts +37 -0
  7. package/src/components/composer/box.ts +85 -0
  8. package/src/components/composer/claude.ts +39 -0
  9. package/src/components/composer/field.ts +47 -0
  10. package/src/components/composer/index.ts +9 -0
  11. package/src/components/composer/pi.ts +37 -0
  12. package/src/components/composer/rail.ts +48 -0
  13. package/src/components/composer/registry.ts +46 -0
  14. package/src/components/composer/rule.ts +55 -0
  15. package/src/components/composer/types.ts +98 -0
  16. package/src/components/editor.ts +564 -259
  17. package/src/components/image.ts +4 -6
  18. package/src/components/loader.ts +1 -9
  19. package/src/components/markdown.ts +487 -423
  20. package/src/components/select-list.ts +67 -15
  21. package/src/components/settings-list.ts +43 -11
  22. package/src/components/text.ts +8 -18
  23. package/src/desktop-notify.ts +1 -1
  24. package/src/fuzzy.ts +63 -6
  25. package/src/index.ts +1 -0
  26. package/src/keybindings.ts +5 -0
  27. package/src/keys.ts +1 -1
  28. package/src/stdin-buffer.ts +130 -20
  29. package/src/terminal-capabilities.ts +36 -6
  30. package/src/terminal.ts +148 -23
  31. package/src/tui.ts +655 -3458
  32. package/src/utils.ts +65 -61
  33. package/dist/types/autocomplete.d.ts +0 -116
  34. package/dist/types/bracketed-paste.d.ts +0 -51
  35. package/dist/types/components/box.d.ts +0 -31
  36. package/dist/types/components/cancellable-loader.d.ts +0 -21
  37. package/dist/types/components/editor.d.ts +0 -166
  38. package/dist/types/components/image.d.ts +0 -165
  39. package/dist/types/components/input.d.ts +0 -25
  40. package/dist/types/components/loader.d.ts +0 -25
  41. package/dist/types/components/markdown.d.ts +0 -92
  42. package/dist/types/components/scroll-view.d.ts +0 -62
  43. package/dist/types/components/select-list.d.ts +0 -69
  44. package/dist/types/components/settings-list.d.ts +0 -123
  45. package/dist/types/components/spacer.d.ts +0 -11
  46. package/dist/types/components/tab-bar.d.ts +0 -89
  47. package/dist/types/components/text.d.ts +0 -28
  48. package/dist/types/components/truncated-text.d.ts +0 -10
  49. package/dist/types/deccara.d.ts +0 -49
  50. package/dist/types/desktop-notify.d.ts +0 -52
  51. package/dist/types/editor-component.d.ts +0 -38
  52. package/dist/types/fuzzy.d.ts +0 -48
  53. package/dist/types/index.d.ts +0 -32
  54. package/dist/types/keybindings.d.ts +0 -197
  55. package/dist/types/keys.d.ts +0 -210
  56. package/dist/types/kill-ring.d.ts +0 -20
  57. package/dist/types/kitty-graphics.d.ts +0 -76
  58. package/dist/types/latex-block.d.ts +0 -8
  59. package/dist/types/latex-to-unicode.d.ts +0 -50
  60. package/dist/types/loop-watchdog.d.ts +0 -49
  61. package/dist/types/mouse.d.ts +0 -67
  62. package/dist/types/stdin-buffer.d.ts +0 -60
  63. package/dist/types/symbols.d.ts +0 -25
  64. package/dist/types/terminal-capabilities.d.ts +0 -324
  65. package/dist/types/terminal.d.ts +0 -175
  66. package/dist/types/tmux.d.ts +0 -6
  67. package/dist/types/ttyid.d.ts +0 -9
  68. package/dist/types/tui.d.ts +0 -480
  69. package/dist/types/utils.d.ts +0 -112
package/CHANGELOG.md CHANGED
@@ -2,2272 +2,5 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [1.0.9] - 2026-08-19
5
+ ## [1.1.0] - 2026-08-25
6
6
 
7
- ## [17.3.5] - 2026-08-16
8
-
9
- ### Fixed
10
-
11
- - Fixed long CPU-bound event-loop stalls being misclassified as system sleep and omitted from loop-blocked diagnostics.
12
- - Fixed focused components with markers falling back to full-screen redraws instead of direct row updates, preserving cursor position and native scrollback across marker changes.
13
-
14
- ## [17.3.4] - 2026-08-14
15
-
16
- ### Fixed
17
-
18
- - Fixed a terminal Device-Attributes reply leaking into the composer as literal text (e.g. `1;22;…;52c`) when it arrived after the startup capability-probe sentinel FIFO drained, a race made observable by the added latency of an SSH/zmx PTY chain. DA1 replies (`CSI ? … c`) and split private-CSI responses are now consumed for the whole session lifetime, not only while a probe sentinel is outstanding ([#8542](https://github.com/can1357/oh-my-pi/issues/8542)).
19
-
20
- ## [17.3.3] - 2026-08-14
21
-
22
- ### Fixed
23
-
24
- - Fixed Gemini reports rendering their final headings and tables as one raw code block when the model emitted a lone closing Markdown fence without its opener.
25
-
26
- ## [17.3.1] - 2026-08-13
27
-
28
- ### Fixed
29
-
30
- - Fixed screen flashing in Herdr panes during transcript streaming.
31
-
32
- ## [17.3.0] - 2026-08-13
33
-
34
- ### Fixed
35
-
36
- - Fixed an issue where repeated pane-width adjustments or terminal resizing could corrupt native scrollback and soft-wrap behavior.
37
- - Fixed an issue where scaled OSC 66 Markdown headings (such as "Large Headings" on Kitty) would render as invisible placeholders or get partially cleared after a redraw or terminal resize.
38
-
39
- ## [17.2.13] - 2026-08-11
40
-
41
- ### Fixed
42
-
43
- - Fixed inline images rendering permanently cropped on Kitty direct-placement terminals (WezTerm, Warp) when an image block straddled the viewport top during streaming: placements are now clipped to the visible slice at write time, and a placement id whose cells reached native scrollback is never re-used ([#8070](https://github.com/can1357/oh-my-pi/pull/8070) by [@voonfoo](https://github.com/voonfoo))
44
-
45
- ## [17.2.12] - 2026-08-08
46
-
47
- ### Fixed
48
-
49
- - Fixed slow Loader paints exceeding their cost-aware CPU duty cycle on WSL/ConPTY when a 200 ms backpressure cap was shorter than the proportional delay ([#8012](https://github.com/can1357/oh-my-pi/issues/8012)).
50
- - Fixed display-math (`$$…$$`) fractions rendering as fragmented text when the numerator and denominator are written on separate source lines: `latexToBlock` treated the top-level newline between `\frac{num}` and `{den}` as a row break, severing `\frac` from its denominator. Such argument-continuation newlines are now preserved so the fraction stays stacked ([#7996](https://github.com/can1357/oh-my-pi/issues/7996)).
51
-
52
- ## [17.2.11] - 2026-08-07
53
-
54
- ### Fixed
55
-
56
- - Fixed an issue where Herdr panes lost native terminal scrollback during TUI transcript replacements or resize redraws.
57
- - Fixed an issue inside tmux where explicit display resets retained stale light/dark palettes and leaked terminal capability bytes into the editor.
58
-
59
- ## [17.2.10] - 2026-08-06
60
-
61
- ### Fixed
62
-
63
- - Fixed a startup crash (EIO error) in multiplexer or SSH sessions when a revoked pty leaves stdin.isTTY active.
64
- - Fixed prompt autocomplete to support Windows drive-absolute paths (e.g., C:/ or C:\).
65
- - Fixed desktop notifications in systemd, tmux, or SSH-attached Linux sessions when DBUS_SESSION_BUS_ADDRESS is unset.
66
- - Fixed an issue where Shift+letter and shifted symbol inputs (such as capital letters, ?, and !) were silently dropped on Windows and WSL terminals using ConPTY (e.g., WezTerm).
67
-
68
- ## [17.2.9] - 2026-08-05
69
-
70
- ### Fixed
71
-
72
- - Fixed table borders (and adjacent cells) inheriting an open inline-code color when a cell's content wraps mid-code-span, by terminating each wrapped cell line's SGR state before the border glyphs ([#7575](https://github.com/can1357/oh-my-pi/issues/7575)).
73
- - Fixed inline images not rendering under WSL + Windows Terminal: the SIXEL capability probe gated on `process.platform === "win32"`, but WSL reports `linux`, so the probe never ran and images fell back to the text placeholder even on Sixel-capable Windows Terminal. The probe now runs on any ConPTY host (native win32 or WSL) ([#6009](https://github.com/can1357/oh-my-pi/issues/6009)).
74
-
75
- ## [17.2.5] - 2026-08-03
76
-
77
- ### Fixed
78
-
79
- - Fixed Kitty and Ghostty keyboard shortcuts on non-Latin keyboard layouts by requesting base-layout key reporting from the terminal.
80
-
81
- ## [17.2.4] - 2026-08-01
82
-
83
- ### Fixed
84
-
85
- - Fixed animated Loader paints saturating a CPU core on slow WSL/ConPTY terminals by applying cost-aware cadence backpressure while preserving 30fps on cheap frames ([#7290](https://github.com/can1357/oh-my-pi/issues/7290)).
86
- - Fixed interactive terminals suppressing all output and input when the host project sets `NODE_ENV=test` or `BUN_ENV=test` ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)).
87
-
88
- ## [17.2.2] - 2026-07-31
89
-
90
- ### Added
91
-
92
- - Added request tokens to explicit OSC 11 appearance refreshes to allow consumers to correlate responses across queued and coalesced terminal probes.
93
-
94
- ### Fixed
95
-
96
- - Fixed the event-loop watchdog incorrectly reporting system sleep or suspension as a synchronous ui.loop-blocked stall.
97
- - Fixed terminal copies of fenced-code blocks retaining margins from components, lists, or blockquotes in assistant messages (#7055 by @GratefulDave).
98
-
99
- ## [17.2.0] - 2026-07-30
100
-
101
- ### Added
102
-
103
- - Added response-level OSC 11 appearance subscriptions to help terminal consumers distinguish confirmed unchanged background classifications from missing replies.
104
-
105
- ### Fixed
106
-
107
- - Fixed native Windows terminal panes freezing their host during forced closure by skipping the stdout-drain wait after ConPTY disconnects.
108
- - Fixed high CPU usage in the Loader spinner during idle waits by optimizing text wrapping and caching during frame updates.
109
- - Fixed hash-prefixed UUIDs in prose being misclassified as 8-digit CSS colors and receiving spurious swatches.
110
- - Fixed unbounded memory growth and potential host freezes when a PTY consumer stalls by capping the pending stdout backlog and treating undrained consumers as a disconnect.
111
-
112
- ## [17.1.8] - 2026-07-28
113
-
114
- ### Fixed
115
-
116
- - Fixed wrapped Markdown list continuations losing their hanging indentation in narrow terminal layouts.
117
- - Fixed an issue where emergency exits from fullscreen overlays could leave the Kitty keyboard protocol active, corrupting Arrow Up input in the terminal after exiting.
118
-
119
- ## [17.1.7] - 2026-07-27
120
-
121
- ### Added
122
-
123
- - Added bulk-input fast path and iterative processing for bracketed paste in the editor
124
- - Added windowed incremental lexing for large markdown documents
125
-
126
- ### Changed
127
-
128
- - Eliminated the dominant markdown streaming CPU cost (73% of a profiled interactive session): marked's GFM `url` tokenizer and `lheading` rule are now gated by O(1)/O(n) charCode pre-checks, the pathological `hr`/`lheading`/`table`/`html` block rules use sticky clones that fail at offset 0 instead of rescanning the source, and the inline math/autolink `start()` scans dropped their regex alternations
129
- - Streaming markdown now freezes the stable prefix through provably closed lists instead of re-lexing everything after the last non-list block on every delta
130
- - Raised the markdown render cache entry budget (32 KiB → 256 KiB) so large messages — exactly the expensive renders — are cacheable
131
- - Deduplicated terminal cursor-visibility writes to skip redundant escape sequences
132
-
133
- ## [17.1.6] - 2026-07-27
134
-
135
- ### Fixed
136
-
137
- - Fixed omp dying with an uncaught `setRawMode failed with errno: 2` instead of exiting 129 when the terminal disconnects. A recycled terminal pane revokes the pty, so the raw-mode restore in `stop()` hit an fd that is no longer a tty; the throw escaped `#markTerminalDisconnected()` and preempted its own SIGHUP. Terminal teardown on the disconnect path is now best-effort, matching `emergencyTerminalRestore()`, so the exit added in [#5837](https://github.com/can1357/oh-my-pi/pull/5837) always runs.
138
- - Fixed the multi-line prompt editor bypassing the keybindings registry for word/line delete and yank: `ctrl+backspace` (a declared default of `tui.editor.deleteWordBackward`) never fired and `keybindings.yml` remaps of `deleteWordBackward`, `deleteWordForward`, `deleteToLineStart`, `deleteToLineEnd`, `yank`, and `yankPop` were ignored, because those actions were matched with hardcoded chords instead of `keybindings.matches(...)` like cursor motion and the single-line `Input` already do ([#6782](https://github.com/can1357/oh-my-pi/issues/6782)).
139
- - Restored the Windows Terminal raw `0x08` → `ctrl+backspace` disambiguation (`WT_SESSION` set, `SSH_*` unset) by routing the exported `matchesRawBackspace` helper through the `matchesKey`/`parseKey` seam. Remote SSH/container sessions where terminal identity is unavailable can opt in with `PI_TUI_RAW_BACKSPACE_IS_CTRL=1` ([#6782](https://github.com/can1357/oh-my-pi/issues/6782)).
140
- - Fixed plain Backspace deleting a whole word inside tmux/GNU screen/Zellij panes launched from Windows Terminal: multiplexers inherit `WT_SESSION` but emit raw `0x08` for plain Backspace, so the automatic raw-backspace → `ctrl+backspace` heuristic misfired. The heuristic now skips multiplexer sessions (`TMUX`/`STY`/`ZELLIJ` or `TERM` starting with `tmux`/`screen`); `PI_TUI_RAW_BACKSPACE_IS_CTRL=1` remains the explicit opt-in everywhere ([#6784](https://github.com/can1357/oh-my-pi/pull/6784)).
141
-
142
- ## [17.1.4] - 2026-07-26
143
-
144
- ### Fixed
145
-
146
- - Prevented inline Kitty graphics from covering full-width overlays such as `/switch`.
147
- - Fixed Ctrl+O (expand tools) truncating the session on ConPTY hosts (native Windows and WSL): the full-view replay routed through the ConPTY frame-truncation intended only for bulk transcript-replacement paints (issue #2115), dropping every row above the retained tail behind an "older lines hidden" marker. The bound now keys on paint intent — bulk replacements (initial resume, `/resume`, handoff, resize geometry rebuilds) stay bounded, while a user-driven `resetDisplay()` (Ctrl+O expand, thinking/setting toggles, display reset) replays the whole transcript ([#4863](https://github.com/can1357/oh-my-pi/issues/4863)).
148
-
149
- ## [17.1.2] - 2026-07-24
150
-
151
- ### Fixed
152
-
153
- - Fixed the terminal flickering when leaving a fullscreen overlay (e.g. `/settings`, the models page) or resizing on terminals that re-report their size whenever the alternate screen buffer toggles: the alt-toggle size echo no longer arms a destructive full-screen (ED3) rebuild, and the in-place repaint path is now auto-detected for any such terminal instead of only Warp ([#6511](https://github.com/can1357/oh-my-pi/issues/6511)).
154
-
155
- ## [17.1.1] - 2026-07-24
156
-
157
- ### Fixed
158
-
159
- - Fixed WarpTerminal wrapping streamed Compatibility Jamo at the platform-default width instead of its rendered one-cell width ([#6461](https://github.com/can1357/oh-my-pi/issues/6461)).
160
-
161
- ## [17.1.0] - 2026-07-24
162
-
163
- ### Added
164
-
165
- - Added Text.setStyleFn() to apply foreground stylers at render time, allowing components to dynamically re-resolve colors after invalidation instead of baking in the palette active at construction.
166
-
167
- ### Fixed
168
-
169
- - Fixed an issue where exiting or tearing down the TUI left the terminal in cursor-key/keypad application mode (DECCKM), which broke arrow keys in the parent shell. Both stop() and emergencyTerminalRestore() now correctly emit standard rmkx resets.
170
-
171
- ## [17.0.9] - 2026-07-23
172
-
173
- ### Added
174
-
175
- - Added `SelectList.setMaxVisible()` so hosts can refit the visible row budget to available height after construction.
176
-
177
- ## [17.0.8] - 2026-07-22
178
-
179
- ### Fixed
180
-
181
- - Fixed an issue where OSC 8 hyperlinks with inline markup corrupted Markdown table column widths.
182
- - Prevented duplicate autocomplete suggestions for slash commands and their matching aliases.
183
- - Fixed terminal background color detection during screen refreshes (Ctrl+L) inside tmux when passthrough is enabled.
184
-
185
- ## [17.0.6] - 2026-07-20
186
-
187
- ### Fixed
188
-
189
- - Fixed idle Loader animations on WSL repeatedly entering render scheduling after an expired ConPTY post-paint settle window instead of resuming direct component writes ([#6024](https://github.com/can1357/oh-my-pi/issues/6024)).
190
-
191
- ## [17.0.5] - 2026-07-18
192
-
193
- ### Changed
194
-
195
- - Improved rendering performance across text, box, editor, and frame layouts by caching validated line widths and avoiding redundant Unicode width measurements.
196
-
197
- ### Fixed
198
-
199
- - Fixed a performance issue where typing in the editor triggered a full UI re-render, significantly improving keystroke responsiveness.
200
- - Restored text wrapping for long descriptions in the slash-command autocomplete picker to ensure readability at standard terminal widths.
201
- - Prevented temporary dashboard frame updates from cluttering the terminal's native scrollback history.
202
- - Added support for cleaning up tracked Kitty graphics, allowing inline images to be properly deleted before falling back to text.
203
- - Fixed an issue where resizing or growing a multiplexer pane would incorrectly overwrite newly exposed rows with blank padding.
204
-
205
- ## [17.0.3] - 2026-07-17
206
-
207
- ### Fixed
208
-
209
- - Fixed multiline pastes arriving without bracketed-paste markers (e.g. Cmd+V in the Codex desktop embedded terminal on macOS) being split into one submit per line: `StdinBuffer` now collects adjacent ESC-free, CR/LF-bearing stdin reads in a fixed 10 ms classification window and coalesces three or more lines into one paste event, while ambiguous one-break input (including Enter batched with a following keystroke) is replayed unchanged ([#5841](https://github.com/can1357/oh-my-pi/issues/5841)).
210
- - Fixed wrapped OSC 8 links in Markdown tables making cell padding, separators, and adjacent cells clickable ([#5885](https://github.com/can1357/oh-my-pi/issues/5885)).
211
- - Fixed interactive sessions surviving terminal closure and entering a runaway render loop by stopping the TUI and raising SIGHUP when terminal input closes or output fails ([#5835](https://github.com/can1357/oh-my-pi/issues/5835)).
212
- - Fixed native cmux SSH pane resizes inserting blank rows into terminal scrollback by routing remote-transport sessions through the in-place repaint path ([#5857](https://github.com/can1357/oh-my-pi/issues/5857)).
213
- - Fixed the terminal flickering when leaving a fullscreen overlay (e.g. `/settings`) on terminals that re-report their size when the alternate screen buffer toggles: the alt-toggle SIGWINCH echo is height-only, so the resize fast path no longer borrows the alternate screen for it ([#5854](https://github.com/can1357/oh-my-pi/issues/5854)).
214
-
215
- ## [17.0.2] - 2026-07-17
216
-
217
- ### Added
218
-
219
- - Added a fullscreen overlay mouse-tracking opt-out to allow selection-first dialogs to preserve native terminal text selection.
220
- - Added `Terminal.refreshAppearance()` to allow consumers to manually trigger a refresh of the detected dark/light terminal appearance without periodic polling.
221
-
222
- ### Fixed
223
-
224
- - Fixed an issue where pressing Enter to accept a mid-prompt `/skill:<name>` autocomplete would submit and clear the draft; it now correctly inserts the skill token and leaves the prompt open.
225
- - Fixed Markdown rendering incorrectly turning local file paths containing `www.` or protocol sequences into HTTP links by requiring a valid GFM left boundary for autolinks.
226
- - Fixed terminal resize behavior by restoring alternate-screen rendering during drag frames, preventing wrapped fragments from polluting native scrollback while preserving the overlay-exit flicker fix.
227
- - Added optional right-border scrollbar to the `Editor` component (`setScrollbarVisible`): shows a thumb glyph on the right border when content overflows `maxHeight`, enabling scrollable multi-line editors (e.g. advisor instructions) without losing the submit hint off-screen.
228
-
229
- ## [17.0.1] - 2026-07-16
230
-
231
- ### Added
232
-
233
- - Added native cmux notification delivery targeted to the current terminal surface.
234
-
235
- ### Fixed
236
-
237
- - Fixed a tmux regression where every non-Kitty pane was forced into legacy keyboard input, collapsing Ctrl+H into Backspace and Shift+Enter into Enter even with `extended-keys on`; the xterm modifyOtherKeys fallback is requested again so tmux honors or ignores it per its own `extended-keys` setting ([#5620](https://github.com/can1357/oh-my-pi/issues/5620)).
238
- - Fixed `@` file-reference and path completion falling through incorrectly inside slash command arguments when command-specific argument completion has no matches ([#5580](https://github.com/can1357/oh-my-pi/issues/5580)).
239
- - Fixed streamed Markdown tables reflowing rows already written to native scrollback when later cells widen a column.
240
- - Fixed fullscreen session-replacement overlays and resize drags exposing stale normal-buffer frames on terminals without effective DEC 2026: asynchronous replacements now keep their overlay visible until the rebuilt transcript is ready, overlay exit is fused into the destructive paint, and resize viewport frames rewrite the normal buffer without alternate-screen switches. Inconclusive DECRQM probes also no longer disable statically detected synchronized output ([#5319](https://github.com/can1357/oh-my-pi/issues/5319)).
241
- - Fixed autocomplete popups moving Windows Terminal IME candidate windows away from the prompt by keeping the terminal cursor anchored at the text insertion point ([#4760](https://github.com/can1357/oh-my-pi/issues/4760)).
242
-
243
- ## [17.0.0] - 2026-07-15
244
-
245
- ### Added
246
-
247
- - Improved LaTeX rendering for \underbrace, \overbrace, \overset, \underset, and \stackrel to use drawn horizontal braces with centered labels and stacked annotations instead of flat inline glyphs.
248
- - Improved LaTeX rendering of multi-letter subscripts and superscripts by displaying them as raised or lowered blocks instead of ragged per-character Unicode glyphs.
249
- - Added an opt-in Editor.setImeSafeCursorLayout() method to protect macOS IME preedit while retaining the compact bordered layout by default.
250
-
251
- ### Fixed
252
-
253
- - Fixed SIXEL image rendering where images with cell heights not divisible by 6 would have their bottom portion overwritten by subsequent content.
254
- - Fixed an issue where the Kitty OSC 99 desktop-notification capability probe would leak raw text into the terminal pane when running inside a multiplexer like tmux or screen.
255
-
256
- ## [16.5.2] - 2026-07-14
257
-
258
- ### Fixed
259
-
260
- - Fixed animated Loader ANSI updates causing unnecessary text layout invalidation and re-wrapping on shimmer-only frames (#5230).
261
- - Fixed Ctrl+W (delete word backward) stopping at underscores in snake_case identifiers, treating them as single words (#4776).
262
- - Fixed automatic file completion incorrectly treating punctuation, trailing spaces, and slash-command text as paths, and improved autocomplete dismissal behavior (#5376).
263
- - Fixed Kitty graphics rendering under tmux, ensuring images correctly follow pane scrolling and reflow (#5381).
264
- - Fixed tmux sessions becoming unresponsive after terminal capability replies by falling back to legacy keyboard input mode when the Kitty protocol is unavailable (#5378).
265
- - Fixed PageUp and PageDown keys on an empty prompt editor incorrectly navigating prompt history instead of scrolling the editor viewport (#4754).
266
-
267
- ## [16.5.1] - 2026-07-14
268
-
269
- ### Fixed
270
-
271
- - Optimized the Markdown rendering cache to prevent large documents from indefinitely occupying cache slots, improving memory usage and performance ([#4820](https://github.com/can1357/oh-my-pi/issues/4820)).
272
- - Fixed viewport corruption on macOS caused by unmanaged stderr writes (such as libmalloc or framework diagnostics) while the terminal is active.
273
- - Fixed an issue where streamed diff code fences retained unhighlighted rows in native scrollback when long transient blocks left the viewport before finalization ([#5126](https://github.com/can1357/oh-my-pi/issues/5126)).
274
- - Fixed native Windows Terminal sessions failing to detect mid-run light/dark theme changes when Mode 2031 appearance notifications are unavailable ([#5091](https://github.com/can1357/oh-my-pi/issues/5091)).
275
- - Hid empty HTML comment separators in Markdown-rendered TUI output instead of displaying them literally ([#4911](https://github.com/can1357/oh-my-pi/issues/4911)).
276
-
277
- ## [16.5.0] - 2026-07-13
278
-
279
- ### Changed
280
-
281
- - Improved native scrollback history management by introducing an optional erase-and-replay mechanism to rebuild scrollback when mutated rows (such as finalized tool blocks or collapsed transcripts) diverge. This is now gated behind the `tui.scrollbackRebuild` setting and defaults to off.
282
-
283
- ### Fixed
284
-
285
- - Fixed a rendering issue where resizing the terminal during forced renders (such as tool finalization or image reconciliation) caused the entire transcript to visibly replay and flicker. Forced renders are now consolidated into a single paint once the resize settles.
286
-
287
- ## [16.4.7] - 2026-07-12
288
-
289
- ### Fixed
290
-
291
- - Fixed keyboard navigation paying an extra frame of input latency after idle; the queue-drain grace now applies only to Ctrl+C and Escape double-press gestures.
292
-
293
- ## [16.4.6] - 2026-07-12
294
-
295
- ### Added
296
-
297
- - Added support for width-changing editor text decorators on standalone presentation lines, with decorated output safely truncated to the available content width.
298
-
299
- ## [16.4.5] - 2026-07-11
300
-
301
- ### Added
302
-
303
- - Added `FuzzyText`, a prepared fuzzy-match handle that builds the search index once and matches many queries against it, optimizing performance for large corpora like session or transcript searches.
304
-
305
- ### Fixed
306
-
307
- - Fixed an issue where the mid-prompt `/` autocomplete popup lingered indefinitely on non-path and non-skill tokens. Autocomplete matching is now properly gated to explicit skill namespaces, queries, and prefixes, preventing stale popups from incorrectly rewriting input on Tab or Enter.
308
- - Fixed idle Loader animation driving the full TUI render pipeline on every spinner tick by directly rewriting the Loader's visible rows when geometry is unchanged, reducing idle render work while preserving fallback repaint paths ([#5192](https://github.com/can1357/oh-my-pi/issues/5192)).
309
-
310
- ## [16.4.1] - 2026-07-10
311
-
312
- ### Added
313
-
314
- - Added full 2-D layout support for display LaTeX math (fractions, matrices, radicals, limits), modeled on the layout approach of [txm](https://github.com/thatmagicalcat/txm) (Terminal TeX Math) by [@thatmagicalcat](https://github.com/thatmagicalcat)
315
- - Added support for `\left`, `\right`, and `\middle` stretchy delimiters in display blocks
316
- - Added rendering for `cases`, `matrix`, `pmatrix`, `bmatrix`, and `vmatrix` environments
317
- - Added support for block-level scripts and big-operator limits (e.g., `\sum`, `\int\limits`)
318
- - Added cross-box styling for `\color`, `\textcolor`, and math font commands (e.g., `\mathbf`)
319
-
320
- ### Changed
321
-
322
- - Improved row alignment and spacing for `align`, `gather`, and `array` environments
323
- - Updated matrix environments to render as baseline-aligned grids with stretched brackets
324
-
325
- ## [16.4.0] - 2026-07-10
326
-
327
- ### Fixed
328
-
329
- - Fixed terminal flickering during session resume, replacement, or resizing on terminals that do not support synchronized output.
330
-
331
- ## [16.3.14] - 2026-07-09
332
-
333
- ### Fixed
334
-
335
- - Fixed race condition where scrollback rows could be incorrectly retracted between render frames
336
-
337
- ## [16.3.13] - 2026-07-09
338
-
339
- ### Fixed
340
-
341
- - Fixed late terminal appearance subscribers missing the already-detected OSC 11 light/dark result, so theme auto-detection picks up the terminal appearance even when the response arrives before the UI subscribes ([#4731](https://github.com/can1357/oh-my-pi/issues/4731)).
342
- - Fixed slash command Tab completion reopening the file autocomplete drawer after accepting no-argument commands ([#4808](https://github.com/can1357/oh-my-pi/issues/4808)).
343
-
344
- ## [16.3.12] - 2026-07-08
345
-
346
- ### Fixed
347
-
348
- - Fixed selector rendering when a legacy theme omits symbol settings by falling back to an ASCII cursor instead of crashing ([#4745](https://github.com/can1357/oh-my-pi/issues/4745)).
349
- - Kept slash command autocomplete rows compact by truncating descriptions instead of wrapping them into multi-line blocks.
350
- - Fixed mid-prompt skill autocomplete so Tab and Enter accept the highlighted `/skill:<name>` suggestion and Backspace dismisses the popup immediately after removing the triggering slash ([#4619](https://github.com/can1357/oh-my-pi/issues/4619)).
351
- - Fixed submitted slash-command arguments treating `@` file-reference tokens as prompt-composer autocomplete triggers when the command does not define argument completions. ([#4600](https://github.com/can1357/oh-my-pi/issues/4600))
352
- - Fixed box-drawing tree lines (`├── item` — directory layouts, decision trees) in prose shearing apart when they wrap: continuation rows now hang under the node text with ancestor rails carried through (`├` → `│`, `└` → blank) instead of restarting at column 0. Applies to prose paragraphs (including inside blockquotes) only when a line with a branch-connector prefix (`├──`, `└─`, …) actually overflows; fitting lines, non-tree prose, and code blocks render byte-for-byte as before.
353
-
354
- ## [16.3.10] - 2026-07-06
355
-
356
- ### Fixed
357
-
358
- - Registered emergency terminal restore with the postmortem fatal path whenever a real terminal starts, so fatal exits restore raw mode/alternate screen on the normal CLI graph (previously the registration was a side effect of a barrel module the CLI never imported).
359
-
360
- ## [16.3.9] - 2026-07-06
361
-
362
- ### Fixed
363
-
364
- - Fixed autocompletion for absolute paths (such as `/tmp/...` or `/Users/...`) at the start of a prompt, ensuring they fall back to file-path completion instead of being incorrectly treated as slash commands.
365
- - Updated absolute path autocompletion behavior so that accepting a suggestion inserts the path without submitting the prompt.
366
-
367
- ## [16.3.7] - 2026-07-05
368
-
369
- ### Fixed
370
-
371
- - Fixed an issue where `@` file-reference tokens in slash-command arguments incorrectly triggered prompt-composer autocompletion when the command did not define argument completions.
372
- - Fixed a memory leak caused by unbounded map growth in the image budget cache.
373
-
374
- ## [16.3.6] - 2026-07-04
375
-
376
- ### Added
377
-
378
- - Added `Markdown.getLastRenderSettledRows()`: the rendered frozen-token-prefix row count of the most recent streaming render, exposed (hard-monotone per text lineage) for native-scrollback commit gating. Frozen-prefix code blocks now syntax-highlight during streaming renders so settled rows stay byte-stable across finalize.
379
-
380
- ### Changed
381
-
382
- - Rewrote the native-scrollback commit law around a visual-record model: whatever scrolls above the viewport enters history exactly once, in order — nothing painted ever vanishes. `NativeScrollbackLiveRegion` is now a single method (`getNativeScrollbackLiveRegionStart`) reporting an exactness boundary: rows below it commit as exact audited bytes; rows above it commit as frozen visual snapshots that are audit-exempt while their source stays live and strict-verified exactly once when the boundary passes them (a divergence recommits the final content below the frozen fragment — duplication, never loss). `getNativeScrollbackCommitSafeEnd`/`getNativeScrollbackSnapshotSafeEnd` and the heuristic promotion machinery they fed are removed.
383
- - Simplified committed-prefix auditing to one hard-verified mark deriving three zones (verified/newly-final/frozen); a frame that shrinks below the committed row count re-bases at the first divergence against the recorded prefix so a collapsing live suffix never re-shows or re-commits already-recorded rows.
384
-
385
- ### Fixed
386
-
387
- - Fixed live tool/eval preview boxes spraying duplicated stale copies into native scrollback mid-run: a still-live block's scrolled rows are now frozen visual snapshots that never re-anchor while it runs; at most one repair happens at finalize.
388
- - Fixed streamed content vanishing above the viewport mid-turn: scrolled-off rows always reach native scrollback (as exact bytes for declared-final content, as visual snapshots otherwise) instead of being deferred invisibly.
389
-
390
- ## [16.3.5] - 2026-07-04
391
-
392
- ### Fixed
393
-
394
- - Fixed the modifyOtherKeys keyboard fallback enabling on unknown SSH terminals, avoiding broken Shift input in iOS SSH clients such as Redock ([#4325](https://github.com/can1357/oh-my-pi/issues/4325)).
395
-
396
- ## [16.3.3] - 2026-07-02
397
-
398
- ### Fixed
399
-
400
- - Fixed keyboard fallback behavior (modifyOtherKeys) on unknown SSH terminals, resolving broken Shift input in iOS SSH clients like Redock.
401
- - Fixed a native scrollback rendering bug where finalized transcript rows below an active block would duplicate when the active block expanded.
402
- - Fixed autocomplete popups remaining active with stale suggestions after destructive text editing (such as Ctrl+W, Ctrl+U, Ctrl+K, Alt+Backspace, Alt+D, paste, or yank), preventing input corruption when pressing Tab or Enter.
403
- - Skipped Markdown re-lex + re-wrap when `setText` receives the identical text, mirroring the equality guard on `Text.setText` — cuts one of the top streaming CPU hotspots when providers re-emit unchanged content ([#4353](https://github.com/can1357/oh-my-pi/issues/4353)).
404
-
405
- ## [16.3.0] - 2026-07-02
406
-
407
- ### Fixed
408
-
409
- - Fixed a potential event loop hang when processing oversized, unterminated terminal escape sequences (OSC/DCS/APC).
410
- - Fixed an issue where large Windows terminal session restores could get truncated mid-frame during ConPTY full-paint resume.
411
-
412
- ## [16.2.13] - 2026-07-01
413
-
414
- ### Fixed
415
-
416
- - Fixed fuzzy-search filtering for CJK and other non-ASCII queries by preserving Unicode letters and numbers during query normalization ([#4114](https://github.com/can1357/oh-my-pi/issues/4114)).
417
-
418
- ## [16.2.12] - 2026-07-01
419
-
420
- ### Fixed
421
-
422
- - Optimized streaming markdown rendering to reuse already-rendered prefix lines and only render new content deltas, improving performance and reducing redraw flicker.
423
-
424
- ## [16.2.10] - 2026-06-30
425
-
426
- ### Fixed
427
-
428
- - Fixed mid-prompt `/skill:<name>` autocomplete acceptance wiping the user's draft. The autocomplete now inserts the `/skill:<name> ` token at the cursor (replacing only the partial `/sk` slash token) and preserves prose typed before and after it, so a user can compose a prompt and reach for a skill without losing their train of thought ([#3913](https://github.com/can1357/oh-my-pi/issues/3913)).
429
-
430
- ## [16.2.9] - 2026-06-30
431
-
432
- ### Added
433
-
434
- - Added `Editor.submit()` to allow programmatic composer submission, enabling integration with speech input and other automated flows.
435
-
436
- ## [16.2.7] - 2026-06-30
437
-
438
- ### Fixed
439
-
440
- - Fixed an issue where a fast double-Escape keypress was swallowed and ignored, preventing double-escape gestures and subsequent Escape key handlers from firing.
441
-
442
- ## [16.2.3] - 2026-06-28
443
-
444
- ### Added
445
-
446
- - Added a desktop notification fallback for Linux terminals using D-Bus (via notify-send or gdbus), enabling completion and prompt notifications in VTE-family terminals (such as GNOME Terminal, Ptyxis, Tilix), Alacritty, and xterm. This is automatically skipped for terminals with native notification support (like VS Code and Warp) and can be disabled using the PI_NO_DESKTOP_NOTIFY=1 environment variable.
447
-
448
- ### Fixed
449
-
450
- - Fixed slash skill autocomplete not opening when there is existing prompt text, ensuring mid-prompt slash lookups correctly display and insert skill commands.
451
- - Fixed modified Enter and keyboard shortcuts in fullscreen overlays for terminals using the xterm modifyOtherKeys fallback (such as iTerm2 when Kitty keyboard negotiation is unavailable).
452
-
453
- ## [16.2.0] - 2026-06-27
454
-
455
- ### Added
456
-
457
- - Added support for rendering HTML <code>, <hr>, and <blockquote> tags with proper theme styling, entity decoding, and layout consistency across Markdown transcripts, table cells, list items, and option labels.
458
- - Added first-class support for Warp terminal (TERM_PROGRAM=WarpTerminal), enabling true color, platform-specific Kitty graphics protocol negotiation for inline images, and safe defaults for OSC 8 hyperlinks and synchronized output.
459
- - Added SelectList.routeMouse() and shared SGR mouse input routing helpers to support fullscreen overlay hit-testing.
460
-
461
- ### Fixed
462
-
463
- - Fixed issues where stray, unmatched, or raw HTML tags would leak into the rendered output.
464
- - Fixed render scheduling to yield behind queued terminal input, preventing delayed Escape key delivery during heavy streaming paints.
465
-
466
- ## [16.1.20] - 2026-06-25
467
-
468
- ### Fixed
469
-
470
- - Recognized Warp (`TERM_PROGRAM=WarpTerminal`) as a first-class terminal, enabling Kitty inline images on macOS/Linux while keeping Warp's unsafe OSC 8 hyperlinks and Windows Kitty graphics disabled ([#3471](https://github.com/can1357/oh-my-pi/issues/3471)).
471
- - Kept queued interrupt keys ahead of ordinary repaints so a slow long-transcript frame cannot consume the Ctrl+C/Esc double-press window before the second key is handled.
472
-
473
- ## [16.1.19] - 2026-06-25
474
-
475
- ### Fixed
476
-
477
- - Fixed bordered `Editor` rendering 1–2 cells past the terminal width when the end-of-line cursor glyph landed past a wide trailing grapheme (CJK comma `,`, emoji, etc.), wrapping the bottom-right corner (`╯`) to its own row. The right chrome (padding + `─` + corner) now shrinks by the exact cursor overflow cell count instead of a 1-cell boolean, so the box stays inside `width` for any `paddingX` ([#3431](https://github.com/can1357/oh-my-pi/issues/3431)).
478
-
479
- ## [16.1.17] - 2026-06-24
480
-
481
- ### Added
482
-
483
- - Added runtime resolution of the Hangul Compatibility Jamo (U+3131..U+318E) display width for terminals known to disagree with the platform default (e.g. Ghostty, which renders these at 2 cells). Fixes doubled/ghosted jamo during Korean IME composition; the resolved width is pushed into the native width engine before the first paint. Other terminals keep the platform default (macOS narrow, otherwise UAX#11), so the override is a no-op outside Ghostty. A runtime DSR/CPR probe for unknown terminals is tracked separately.
484
- - Added `setHangulCompatibilityJamoWidth` / `getHangulCompatibilityJamoWidth` to set the jamo width profile (`"platform" | "unicode" | 1 | 2`); the profile is mirrored into the native `setHangulCompatJamoWidthOverride`.
485
-
486
- ### Fixed
487
-
488
- - Removed the 30-second OSC 11 background-color poll that ran on terminals without DEC Mode 2031 support (macOS Terminal.app, Warp, VS Code's built-in terminal, older Alacritty/WezTerm). Each poll's OSC 11 + DA1 write wiped the user's active text selection on several of those terminals, causing intermittent "can't copy" failures whenever a poll fired mid-drag — most visibly during the Ask tool dialog when the user wants to quote text back from the conversation ([#3297](https://github.com/can1357/oh-my-pi/issues/3297)). Theme detection now relies on the initial startup probe plus Mode 2031 push notifications; affected terminals pick up OS-theme changes on next launch.
489
- - Fixed `@`-path autocomplete failing on Windows for paths outside the cwd. Windows absolute paths (e.g. `C:\\Users\\...`) were not detected as absolute — only `/` was checked — so they were incorrectly joined with the base directory, producing invalid search paths and empty suggestions. Path-join calls also introduced backslashes into suggestion values, breaking round-trip insertion. Absolute path detection now uses `path.isAbsolute()` (handles drive letters) and suggestion paths are normalized to forward slashes (valid on all platforms).
490
- - Fixed settings rows crashing native text truncation when a malformed config value reaches the renderer as a non-string ([#3338](https://github.com/can1357/oh-my-pi/issues/3338)).
491
- - Fixed desktop notifications being silently lost under tmux on the common stack of tmux + kitty/ghostty/wezterm/iTerm2. `TERMINAL_ID` resolves to the inner terminal (whose markers leak into the tmux session env), which maps to `NotifyProtocol.Osc9` / `NotifyProtocol.Osc99`, and `sendNotification()` wrote that raw OSC straight to stdout — tmux dropped it on the floor and `monitor-bell` / `monitor-activity` never fired, so a backgrounded omp pane had no way to flag completion or `ask` blockage. Under `TMUX`, OSC-protocol notifications are now wrapped in tmux's `\x1bPtmux;…\x1b\\` DCS passthrough envelope (so users with `set -g allow-passthrough on` still get the real toast on the outer terminal) and followed by a `\x07` BEL (so `set -g monitor-bell on` reliably flags the window otherwise). The OSC 99 capability probe in `terminal.ts` is wrapped the same way so rich notifications keep working across tmux. `NotifyProtocol.Bell` paths are unchanged. ([#3395](https://github.com/can1357/oh-my-pi/issues/3395))
492
-
493
- ## [16.1.10] - 2026-06-21
494
-
495
- ### Fixed
496
-
497
- - Fixed streaming output being lost from native scrollback below a commit-unstable "barrier" block (a provisional/collapsed tool preview, a displaceable `job` poll, or a reflowing-markdown reply) once the content under it overflowed the viewport. The engine committed native scrollback only up to the barrier's seam, so rows that scrolled above the window under the barrier were committed nowhere and repainted nowhere — they vanished, and a later shift/finalize/removal of the barrier silently dropped the rows beneath it. The append-only commit floor is now `windowTop` in every non-frozen paint path (ordinary update, shrink re-slice, full paint), so whatever scrolls above the window always reaches history; the seam boundaries now only classify which committed rows stay byte-stable-audited vs. durable-exempt. The committed-prefix audit is range-aware: it audits the forced-overflow suffix in full (re-anchoring — duplication, never loss — when a barrier finalizes), exempts the durable middle (a streaming table re-aligning its columns) from re-anchor spray, and runs a full hard scan of rows a frame newly marks permanent so a single-row finalize edit far above the commit boundary still re-anchors instead of being dropped.
498
-
499
- ## [16.1.8] - 2026-06-20
500
-
501
- ### Added
502
-
503
- - Added an optional synchronous dynamic description hook for slash-command autocomplete items.
504
-
505
- ### Fixed
506
-
507
- - Fixed Markdown component to strip inline `<span>` and `<text>` tags while preserving their contents and unescaping nested HTML entities (`&lt;`, `&gt;`, `&quot;`, `&apos;`, `&amp;`), preventing raw LLM block/inline formatting residues from leaking into rendered TUI output.
508
-
509
- ## [16.1.7] - 2026-06-20
510
-
511
- ### Fixed
512
-
513
- - Fixed slash command autocomplete, inline hints, and Enter completion when the slash command is preceded by leading whitespace ([#3095](https://github.com/can1357/oh-my-pi/issues/3095)).
514
- - Fixed empty `/` autocomplete burying user skill commands below every built-in command, so installed skills appear in the initial slash popup ([#2875](https://github.com/can1357/oh-my-pi/issues/2875)).
515
-
516
- ## [16.1.0] - 2026-06-19
517
-
518
- ### Added
519
-
520
- - `Box` now accepts an optional `border` (box-drawing glyphs + colorizer) and exposes `setBorder()`, drawing a colored outline around its padded/background content. The border is automatically dropped at widths too narrow to frame so a bordered box never overflows its given width.
521
-
522
- ## [16.0.11] - 2026-06-19
523
-
524
- ### Breaking Changes
525
-
526
- - Removed `getIndentation` and `getIndentationNoescape` exported utilities
527
- - Tab-related operations no longer respect per-file or globally configured indentation settings
528
-
529
- ### Changed
530
-
531
- - Standardized tab expansion to use a fixed display width instead of configurable settings
532
- - Removed support for custom tab width configuration in text rendering and input handling
533
-
534
- ### Fixed
535
-
536
- - Corrected logic in string truncation to prevent improper truncation of short strings
537
- - Fixed a one-frame transcript flash during a non-multiplexer resize drag: while the drag borrowed the alternate screen and painted only the viewport, any ordinary (non-forced) render from a still-animating block — a tool spinner tick, a streamed token, a cursor blink — fell through to the deferred geometry-rebuild full paint, which left the alternate screen to repaint the whole transcript on the normal screen for a single frame before the next SIGWINCH re-entered the viewport fast path, so a live tool block flashed in and vanished. Ordinary renders mid-drag now stay on the viewport fast path; only forced renders (tool finalization, reset, image reconciliation) still preempt it.
538
-
539
- ## [16.0.10] - 2026-06-18
540
-
541
- ### Fixed
542
-
543
- - Fixed Markdown renderer rendering raw HTML tags (like `<br>`, `<li>`, `<ul>`, `<ol>`, and `<p>`) literally in the terminal by parsing and converting them to appropriate terminal formatting, preserving repeated HTML line breaks, nested HTML list indentation, ordered list numbering, paragraph-wrapped list item markers, paragraph separation, and table sizing after HTML line breaks.
544
- - Fixed animated working-message loader frames repainting at 30fps on terminals without synchronized-output support, which could cause visible flicker during normal prompt rendering ([#2771](https://github.com/can1357/oh-my-pi/issues/2771)).
545
-
546
- ## [16.0.9] - 2026-06-18
547
-
548
- ### Fixed
549
-
550
- - Fixed bottom-anchored fullscreen overlays keeping their body rows but clipping off footer actions when terminal-height clamping is applied, restoring plan-mode approval options on short or stale-size terminals ([#2957](https://github.com/can1357/oh-my-pi/issues/2957)).
551
-
552
- ## [16.0.8] - 2026-06-18
553
-
554
- ### Fixed
555
-
556
- - Fixed bracketed paste under kitty+tmux leaking `[27;5;106~` escape tails throughout the pasted text (newlines became visible garbage instead of line breaks). tmux's default `extended-keys-format=xterm` re-encodes paste control bytes as `modifyOtherKeys` sequences (`ESC[27;5;<code>~`), which the paste sanitizer did not decode — only the sibling `csi-u` form (`ESC[<code>;5u`) was handled. Both forms are now decoded back to their literal control byte (Ctrl+J → "\n") before control-character stripping, and the decoder is shared by the multi-line editor and the single-line modal input.
557
-
558
- ## [16.0.5] - 2026-06-17
559
-
560
- ### Added
561
-
562
- - Added tight layout support (`setTuiTight`/`getPaddingX`) to dynamically remove 1-character horizontal padding from Text, Markdown, Box, and TruncatedText components.
563
-
564
- ### Changed
565
-
566
- - Coalesced byte-adjacent SGR sequences in emitted lines into a single `CSI … m`. The component tree styles each span as `<set>text<reset>`, so adjacent spans emit runs of back-to-back SGR sequences (e.g. a `CSI 39 m` fg-reset immediately followed by the next span's `CSI 38;2;r;g;b m`); merging the run is behavior-preserving because SGR parameters apply left-to-right regardless of framing. On a real transcript this drops ~30-40% of all SGR sequences, cutting the per-frame byte volume and SGR-dispatch count a slow terminal engine (e.g. xterm.js/WebGL under a large viewport) must process. Each emitted sequence is capped at 16 parameter tokens so a long adjacent run is split across several valid CSIs instead of overflowing a terminal's parameter buffer (xterm.js caps at 32 and silently truncates, corrupting colors). A run is never extended past a parameter list that ends in an incomplete semicolon-form extended color (`38/48/58;2` missing a channel or `;5` missing the index), so a following code can't be absorbed as the missing component. Disable with `PI_NO_SGR_COALESCE=1`.
567
-
568
- ### Fixed
569
-
570
- - Fixed image cache invalidation when terminal image protocol, Kitty placeholder mode, or cell dimensions change, preventing stale rendered output
571
- - Fixed direct inline-image placements leaving the cursor inside the reserved image block, which let following chat rows overwrite the middle of rendered screenshots ([#2863](https://github.com/can1357/oh-my-pi/issues/2863)).
572
- - Fixed inline-image replay after startup or resume fallback paints by invalidating cached image rows when the terminal image protocol, Kitty placeholder mode, or cell dimensions change.
573
-
574
- ## [16.0.3] - 2026-06-16
575
-
576
- ### Added
577
-
578
- - Added `\tfrac` support to stacked display-math rendering so it now displays as a vertical fraction in `latexToBlock` output
579
- - Added markdown parsing for own-line display-math blocks (`$$...$$` and `\[...\]`) and delimiter-free `\begin{...}...\end{...}` math environments so block equations render via LaTeX-to-Unicode
580
- - Added stacked rendering of display-math fractions (`\frac`, `\dfrac`, `\cfrac`): the numerator is drawn over a horizontal bar over the denominator, with surrounding terms and `align`/`equation`-style environment rows aligned to the bar. Triggered for own-line `$$`/`\[` blocks, bare `\begin{...}` environments, and a paragraph whose sole content is a single display-math span; inline `$...$` fractions stay single-line (`½`, `(a+b)/c`)
581
- - Added bare math auto-rendering in `renderMathInText` for math-shaped lines and math environment blocks that omit `$`/`\(` delimiters
582
- - Added LaTeX-to-Unicode rendering for markdown math spans, converting `$$...$$`, `$...$`, `\(...\)`, and `\[...\]` into readable Unicode in Markdown output
583
- - Exported LaTeX conversion helpers from the package entrypoint so consumers can call `latexToUnicode`, `latexToBlock`, `renderMathInText`, `inlineMathSpanEnd`, and `isBareMathEnvironment` directly
584
- - Expanded LaTeX-to-Unicode conversion coverage for additional math fonts, delimiters, extensible arrows, layout environments, cancel/brace annotations, references, and AMS symbols
585
- - Added ANSI color rendering for LaTeX `\textcolor`, scoped `\color`, `\colorbox`, and `\fcolorbox`, including xcolor/CSS color parsing and truecolor/256-color terminal output
586
- - Added an optional `maxWidth` parameter to `MarkdownTheme.resolveMermaidAscii` to allow diagram resolvers to fit ASCII output to the available content width
587
-
588
- ### Changed
589
-
590
- - Changed markdown math rendering to preserve multiline layout for display equations, keeping `\\` row breaks as separate output lines (including inside list items)
591
-
592
- ### Fixed
593
-
594
- - Fixed `alignat`/`alignedat`/`gatheredat` rendering in `latexToBlock` so the required `{n}` preamble is not rendered as visible math content
595
- - Fixed math parsing to leave non-math LaTeX snippets (for example `\begin{itemize}`) and fenced code blocks as literal text instead of rendering them as math
596
- - Fixed `renderInlineMarkdown` to handle top-level display-math tokens so raw `$$...$$` delimiters are no longer leaked
597
- - Fixed inline math span detection so escaped dollars and currency-like patterns (such as `$5` and `$10`) are not converted as math
598
- - Fixed Mermaid diagram rendering in Markdown code blocks to clip each ASCII line to content width before wrapping, preventing preformatted diagram rows from fragmenting
599
- - Fixed fullscreen overlays losing keyboard focus to hidden prompt surfaces, which could make settings unresponsive while a background approval request was pending ([#2789](https://github.com/can1357/oh-my-pi/issues/2789)).
600
- - Fixed `bun test` runs inside a real terminal leaking TUI output: `ProcessTerminal` now honors a headless test-runtime default, so frame paints, `start()` capability probes (OSC 11 / DA1 / kitty), the progress keepalive, notifications, and teardown escapes no longer reach the developer's terminal, and stdin raw mode is never engaged. Previously `#safeWrite` only skipped on `!process.stdout.isTTY`, so a developer running the suite in an interactive terminal saw stray status/editor boxes and probe queries. Terminal-contract suites opt back into real I/O via `setTerminalHeadless(false)`
601
-
602
- ## [16.0.2] - 2026-06-16
603
-
604
- ### Fixed
605
-
606
- - Fixed VS Code integrated terminal keypad digit CSI-u input being handled as navigation instead of text.
607
- - Fixed xterm-compatible terminals scrolling the native viewport to the bottom on prompt-editor keypresses by disabling `?1010`/`?1011` while the TUI owns the TTY and restoring the prior set modes on exit ([#2732](https://github.com/can1357/oh-my-pi/issues/2732)).
608
- - Fixed CMUX sessions being treated as direct terminals during resize/reset because they do not set `TMUX`/`STY`/`ZELLIJ` and may run with `TERM=dumb`; the renderer now treats CMUX workspace/surface env markers as multiplexer signals and preserves pane scrollback instead of emitting ED3 (`CSI 3 J`).
609
- - Fixed a self-sustaining resize-redraw storm in Warp: the non-multiplexer resize fast path borrows the alternate screen, and Warp re-reports a one-row-different size whenever the alt buffer is toggled, so each drag frame fed back a fresh resize event and the TUI flooded ED3 full repaints with stable geometry. Resize now repaints in place (no alt-screen borrow, no ED3 rewrap) on terminals that re-report size on alt-screen toggles, matching the multiplexer path. Overridable with `PI_TUI_RESIZE_IN_PLACE=1|0`.
610
-
611
- ## [16.0.1] - 2026-06-15
612
-
613
- ### Added
614
-
615
- - Added Zellij and WezTerm pane environment fallbacks for terminal-specific session continuation when no TTY path is available.
616
-
617
- ### Fixed
618
-
619
- - Fixed slash command autocomplete acceptance replacing only a stale rendered prefix, which could leave fast-typed characters before `/skills:` completions and corrupt the submitted command ([#1745](https://github.com/can1357/oh-my-pi/issues/1745)).
620
-
621
- ## [15.13.1] - 2026-06-15
622
-
623
- ### Added
624
-
625
- - Added volatile speech-to-text preview support to `Editor` with `setVolatileText(text)`, `clearVolatileText()`, and `commitVolatileText(text)` so hosts can replace, discard, or commit live dictated text at the cursor without appending
626
- - Added an always-on `LoopWatchdog` armed in `TUI.start()`/`TUI.stop()` that logs `ui.loop-blocked` (rising-edge deduped, with `blockedMs` and the phase active during the elapsed interval) when a self-scheduled probe tick runs late, plus a `ui.select-filter` breadcrumb around the `SelectList` fuzzy filter. The phase is read via `takeRecentLoopPhase`, so a synchronous block whose breadcrumb was pushed and popped before the delayed tick runs is still attributed to its phase instead of "unknown". `stop()` cancels the armed timer (via `clearTimeout` on the default handle) so repeated start/stop cycles leave no pending probe, with the generation guard as a fallback ([#2485](https://github.com/can1357/oh-my-pi/issues/2485))
627
- - Added `ctrl+j` as a second default binding for the `tui.input.newLine` action alongside `shift+enter`, so terminals that cannot emit `shift+enter` still have a newline key. On terminals with Kitty-protocol / `modifyOtherKeys` disambiguation `ctrl+j` inserts a newline while `Enter` still submits; on legacy terminals where `ctrl+j` and `Enter` are both byte-identical `LF` it submits (documented limitation). User keybinding overrides still take precedence ([#2473](https://github.com/can1357/oh-my-pi/issues/2473))
628
- - Added an `Editor.onLargePaste(text, lineCount)` hook, fired for a "marker-sized" paste (the point where the editor would otherwise collapse it into a `[Paste #N]` token). Returning `true` lets the host intercept the paste — e.g. to offer wrap-in-code-block / wrap-in-XML / attach-as-file choices — and suppresses the default marker (no undo state is recorded). Added `Editor.insertPaste(content)` so the host can re-insert a (possibly transformed) collapsed paste marker without re-triggering the hook.
629
- - Added `Editor.deleteBeforeCursor(count)`, which removes up to `count` characters immediately before the cursor on the current line (capped at the cursor column, single line, records one undo state). Hosts use it to "track back" optimistically-inserted characters — e.g. the coding-agent hold-`Space` push-to-talk gesture deleting the space-bar auto-repeat burst.
630
- - Added an optional `getNativeScrollbackSnapshotSafeEnd()` to the `NativeScrollbackLiveRegion` contract: a *durable* commit boundary (D ≥ the byte-stable `commitSafeEnd`) for live rows whose current snapshot is permanent content but may still drift bytes later (a streaming markdown table re-aligning its columns). The engine commits these rows when they scroll above the window — never dropping them — but **audit-exempt** (tracked via a new byte-stable `auditRows` prefix), so a later layout change of an already-committed row freezes a stale row in history (duplication never loss) instead of re-anchoring the committed-prefix audit and spraying duplicate snapshots. Components that omit it are unchanged: `durableBoundary === byteStableBoundary` and `auditRows === committedRows`, so the ledger math is byte-identical.
631
-
632
- ### Fixed
633
-
634
- - Fixed overlays without an explicit `maxHeight` dropping their bottom rows off-screen when taller than the terminal: `#resolveOverlayLayout` now defaults the height cap to the available rows, so a tall overlay is sliced to fit (and re-clamps on resize) instead of overflowing the visible region.
635
- - Fixed `Editor.#decorate` rejecting keyword matches glued to the cursor: `CURSOR_MARKER` begins with ESC (non-whitespace), so decorators with a right-boundary lookahead (e.g. `/(?<!\S)ultrathink(?!\S)/`) failed at the seam and dropped highlighting until a trailing character was typed. The decorate hook now splits around the marker and decorates each user-text segment in isolation so word-boundary lookarounds resolve correctly on both sides ([#2475](https://github.com/can1357/oh-my-pi/issues/2475)).
636
- - Fixed non-multiplexer resize drags with width changes briefly showing terminal-reflowed wrapped fragments: transient resize frames now borrow the alternate screen and return to the normal screen for the settled authoritative replay.
637
- - Fixed `isMultiplexerSession()` only checking the `TMUX`/`STY`/`ZELLIJ` env vars and missing the `TERM=tmux-*`/`screen-*` fallback every sibling detector uses. When the multiplexer env was stripped but `TERM` survived (`sudo` without `-E`, `su`, env-sanitizing launchers/ssh), the renderer misclassified the pane as a direct terminal and emitted ED3 (`CSI 3 J`) on resize/replace/`resetDisplay`, which wipes tmux pane history — scrollback only reappeared after a full rerender (Ctrl+L). The check now aligns with `shouldEnableSynchronizedOutputByDefault`, `detectRectangularSgrSupport`, and `getFallbackImageProtocol` in `terminal-capabilities.ts` ([#2544](https://github.com/can1357/oh-my-pi/issues/2544)).
638
-
639
- ## [15.12.6] - 2026-06-14
640
-
641
- ### Fixed
642
-
643
- - Fixed live transcript rows duplicating into native scrollback during a non-multiplexer resize drag: the viewport fast-path repaint now parks the hardware cursor at the real content bottom (mirroring the authoritative paint) instead of the padded viewport bottom, so a subsequent height shrink no longer scrolls live rows into history before the settle replay
644
- - Fixed inline images flipping to their text fallback during a non-multiplexer resize drag: the viewport fast path now drives the image budget as a stable partial pass that replays the committed per-image live/text split by id, instead of deriving it from the reversed, tail-only walk order
645
-
646
- ## [15.12.5] - 2026-06-13
647
-
648
- ### Added
649
-
650
- - Added `ViewportTailProvider` to let child components provide their visible tail rows during fast-path non-multiplexer resize rendering
651
- - Added `TUI.resizeViewportPaints` and `TUI.resizeViewportActive` getters to expose deferred resize viewport repaint diagnostics
652
-
653
- ### Changed
654
-
655
- - Changed non-multiplexer terminal resize handling so each SIGWINCH paints only the visible viewport and defers the full rewrap and native scrollback replay until the resize settles
656
-
657
- ### Fixed
658
-
659
- - Fixed issue #2088 viewport flash and repeated full rewrites during rapid terminal drags outside multiplexers by replaying the full transcript only after the resize settle window
660
-
661
- ## [15.12.4] - 2026-06-13
662
-
663
- ### Added
664
-
665
- - `PI_FORCE_HYPERLINKS=1` / `PI_NO_HYPERLINKS=1` env overrides for the OSC 8 hyperlink capability, mirroring the `PI_FORCE_SYNC_OUTPUT`/`PI_NO_SYNC_OUTPUT` shape (opt-out beats force-on).
666
-
667
- ### Changed
668
-
669
- - Auto-enable OSC 8 hyperlinks inside tmux when tmux self-reports >= 3.4 via `TERM_PROGRAM_VERSION`; tmux 3.4 stores OSC 8 as a cell attribute and forwards it to outer terminals whose `terminal-features` include `hyperlinks`. Older tmux, GNU screen, and tmux without a reported version still default off. Resolution is factored into `hyperlinksUserOverride()` and `shouldEnableHyperlinksByDefault()` mirroring the sync-output helpers ([#2403](https://github.com/can1357/oh-my-pi/issues/2403)).
670
-
671
- ## [15.11.8] - 2026-06-12
672
-
673
- ### Changed
674
-
675
- - Markdown rendering during streaming re-lexes only the grown tail instead of the whole buffer on every reveal tick. marked has no resumable lexer, but block tokenization is local across a blank-line boundary with balanced fences, so the largest blank-line-bounded prefix's block tokens are frozen and reused (`lex(prefix) ++ lex(tail)`), with a full-lex fallback for non-append edits, reference-link definitions, and CRLF input. The output is byte-identical to a full lex (covered by a contract test), turning the O(N²) cost of revealing a long single-block message into O(N): a 6,000-grapheme reveal dropped from ~575 ms to ~89 ms of CPU in benchmarks.
676
-
677
- ## [15.11.5] - 2026-06-12
678
-
679
- ### Added
680
-
681
- - Added `fuzzyRank` to return sorted matches together with a fuzzy score
682
- - Added a configurable `Input.prompt` field (defaults to `"> "`; set to `""` for chrome-less embedding inside custom banners)
683
-
684
- ### Changed
685
-
686
- - Changed fuzzy matching to normalize queries and text into words, including camelCase and punctuation separators, before scoring
687
- - Changed `Input.setValue` to place the cursor at the end of the new value instead of clamping it to its previous position, so typing after seeding a prefilled value appends rather than prepends
688
-
689
- ### Fixed
690
-
691
- - Fixed multi-word searches so `fuzzyMatch` no longer matches when query letters are only scattered across unrelated words
692
-
693
- ## [15.11.4] - 2026-06-12
694
-
695
- ### Added
696
-
697
- - Added `partialHoldTimeout` to `StdinBufferOptions` to control the maximum extra delay held for unambiguous incomplete escape sequences before they are flushed
698
- - Added `SettingsList.sidebarWidth` option for a fixed split-layout sidebar width
699
- - Added mouse pointer support APIs to `SettingsList` with `setHoverItem`, `hitTest`, `hoverTest`, and `routeSubmenuMouse` for row targeting and submenu routing
700
- - Added `SettingsList.setMaxVisible(rows)` and `SettingsList.handleWheel(delta)` for dynamic viewport sizing and mouse-wheel step selection
701
- - Added compact tab features with new `Tab.short` labels and `TabBar.selectTab(id)` for id-based activation of non-muted tabs
702
- - Added pointer-hover and hit-testing APIs to `TabBar` with `setHoverTab`, `tabAt`, and `hoverTab` theme
703
- - Added exported SGR mouse utilities `parseSgrMouse`, `SgrMouseEvent`, and `MouseRoutable`
704
- - Added section support to `SettingsList`: `SettingItem.heading` rows split the list into sections, PgUp/PgDn (`tui.select.pageUp`/`pageDown`) jump between sections (or page when none exist), and wide renders use a split layout — section sidebar on the left, the active section's items on the right — falling back to inline heading rows when the width cannot fit both panes. Headings are skipped by navigation, excluded from search, and styled through the optional `SettingsListTheme.heading` (which receives a `dimmed` flag for headings outside the active section) and `section`.
705
- - Added a host-integration surface to `SettingsList`: a `SettingsListOptions` constructor arg (`layout` to force the flat layout, `typeToSearch: false` to hand the query to a parent, `emptyText`, `hint`), `selectItem(id)`, `getSelectedItem()`, `onSelectionChange`, `hasOpenSubmenu()`, and the exported `getSettingItemFilterText` helper.
706
- - Added keyboard section focus to `SettingsList`: `toggleSectionFocus()` / `sectionFocused` / `hasSectionFocusTargets()` flip Up/Down between row navigation and whole-section jumps — the cursor glyph parks on the active sidebar entry (or the active heading row in the flat layout) while the row cursor hides, Enter/Esc drop focus back to the rows, and any explicit row selection (`selectItem`, wheel, filtering) exits it.
707
- - Added muted tabs to `TabBar` (`Tab.muted` + `TabBarTheme.mutedTab`, skipped by keyboard navigation), `setTabs(tabs, activeId?)`/`setActiveById(id)` for re-rendering the strip without firing `onTabChange`, an optional empty label (drops the `Label:` prefix), and a `showHint` switch for the trailing "(tab to cycle)" hint.
708
-
709
- ### Changed
710
-
711
- - Changed `SettingsList` section-focused keyboard handling so `Up`/`Down` now jump between sections and `Enter`/`Escape` exit section focus before confirming or cancelling a setting
712
- - Changed `SettingsList` split layout at wide widths to render the full list in the right pane and dim items outside the active section instead of showing only the active-section rows
713
- - Changed `SettingsList` to omit the default hint row (and preceding blank line) when `options.hint` is set to an empty string
714
- - Changed tab-bar overflow handling to collapse tabs to their `short` forms before wrapping to multiple lines
715
-
716
- ### Fixed
717
-
718
- - Fixed `StdinBuffer` handling of split SGR mouse reports so fragmented sequences are reassembled instead of leaking their tail bytes as literal input
719
- - Fixed Esc being unreliable (or seconds-slow) inside fullscreen overlays such as `/settings` on kitty-protocol terminals (Ghostty/kitty): the kitty keyboard mode stack is per-screen, so entering the alternate screen silently reverted keys to legacy encoding while the app still parsed them as kitty input. The TUI now re-pushes the active kitty flags right after `\x1b[?1049h` and pops them before `\x1b[?1049l`.
720
- - Fixed `StdinBuffer` tearing a buffered bare `ESC` followed by another escape sequence: the `\x1b\x1b` candidate was consumed as alt+esc before the CSI/SS3 continuation byte was ever inspected, swallowing the Esc keypress and leaking the follower's tail (`[B`, `[<35;22;17M`) as typed text into focused components. Meta-CSI chords (`\x1b\x1b[A`) now stay whole, and `ESC` + SGR mouse report is split into a real Esc keypress plus a parseable report.
721
- - Lowered `PARTIAL_HOLD_MAX_MS` from 500ms to 150ms so a dangling escape partial that never completes (e.g. a bare `ESC` arriving while the kitty-active flag is stale) is delivered after at most ~200ms instead of half a second.
722
- - Fixed deferred partial-flush behavior so pending incomplete escapes are not split across timer boundaries and can still complete when the next chunk arrives
723
- - Fixed kitty keyboard-mode handling of a dangling `ESC` so it can be joined with subsequent CSI mouse/kitty input instead of being emitted as a standalone sequence
724
- - Fixed `SettingsList` to clear section-focus state when filtering items, changing data, scrolling with the mouse wheel, or selecting by ID so stale heading focus does not persist across interactions
725
- - `SettingsList` now renders every state — list, open submenu, filtered results, empty — at one stable height, so interacting with a bottom-anchored settings panel no longer resizes the live terminal region on each keystroke (which forced re-anchoring and could strand stale scrollback rows).
726
-
727
- ## [15.11.3] - 2026-06-11
728
-
729
- ### Fixed
730
-
731
- - Fixed the root compose letting a lower child's native-scrollback live seam overwrite a higher one: the topmost seam (and its commit-safe extension) now defines the commit boundary, so a status loader below a streaming transcript can no longer cause still-mutable transcript rows to be committed as stale history ([#2328](https://github.com/can1357/oh-my-pi/pull/2328)).
732
-
733
- ## [15.11.2] - 2026-06-11
734
-
735
- ### Fixed
736
-
737
- - Fixed Ctrl+C/exit corrupting the parent shell on Windows: `emergencyTerminalRestore()` wrote `\x1b[?1049l` (leave alternate screen) unconditionally on every exit path, and conhost/Windows Terminal execute an unconditional cursor restore for it even when the alt buffer was never entered — with no prior save the cursor jumped to the viewport home, so the shell prompt landed on top of the dead frame. The leave sequence is now gated on tracked alt-screen state (set/cleared by the TUI's fullscreen-overlay enter/leave and stop paths).
738
- - Skipped native syntax highlighting for transient markdown streaming renders, including nested list code blocks, leaving code blocks plain until their content stabilizes to avoid main-thread highlighter spikes.
739
-
740
- ## [15.11.1] - 2026-06-11
741
-
742
- ### Added
743
-
744
- - Added `TUI.requestComponentRender(component)` to schedule component-scoped renders for self-contained updates
745
-
746
- ### Changed
747
-
748
- - Changed the render pipeline to reuse only affected root subtrees for component-scoped updates, avoiding full-tree compose when animations or other isolated component changes occur
749
-
750
- ### Fixed
751
-
752
- - Fixed component-scoped renders to preserve prior live scrollback seam data for skipped root children, preventing duplicate or missing rows during spinner-only updates
753
- - Reported committed native scrollback row counts to interested child components so immutable history can be skipped without breaking live-region commit bookkeeping.
754
- - Fixed `ProcessTerminal` treating asynchronous stdout `EIO` errors as uncaught exceptions: stdout `error` events now mark the terminal dead, disable future renders, and keep the active session process alive ([#2284](https://github.com/can1357/oh-my-pi/issues/2284)).
755
-
756
- ## [15.11.0] - 2026-06-10
757
-
758
- ### Added
759
-
760
- - Added support for asynchronous `onSubmit` handlers by allowing the callback to return a `Promise<void>`
761
-
762
- ## [15.10.11] - 2026-06-10
763
-
764
- ### Added
765
-
766
- - `SettingsList` now supports type-to-search filtering with Escape clearing an active query before canceling.
767
-
768
- ### Changed
769
-
770
- - Preserved list selection by item ID when replacing settings so focus stays on the same setting
771
- - Displayed a no matching settings message and search-editing hint when filtering returns no matches
772
- - Expanded settings search matching to include IDs, current values, descriptions, and option values as well as labels
773
- - Raised the stdin split-escape flush window from 10ms to 50ms: over laggy links (ssh, slow multiplexers) a CSI sequence split across reads was flushed as literal data, leaking `[` + `A` style fragments into the editor as typed text
774
- - Lengthened the OSC 11 appearance poll on terminals without Mode 2031 from 2s to 30s — each poll's query write cleared the user's active text selection, breaking copy every two seconds on Alacritty/Warp/older WezTerm
775
- - Rewrote `StdinBuffer.extractCompleteSequences` to index-based scanning: the previous per-iteration `slice` + `Array.from(remaining)[0]` made plain-text bursts O(n²), turning a 100KB non-bracketed paste into a multi-second freeze
776
- - Capped the editor undo stack at 100 entries with word-level coalescing of consecutive single-character inserts (matching `Input`), capped the kill ring at 60 entries, cached word-wrap layout per (line, width) so each render and key handler shares one wrap pass, and batched ≤1000-char single-line pastes into one insert + one trigger-detection pass instead of per-character replay
777
- - Virtualized the frame pipeline around a stable-prefix contract — the renderer no longer does O(total transcript) work per frame. `Component.render` now returns `readonly string[]`: results are component-owned, callers must not mutate them, and an unchanged component returns the same array reference (reference equality proves byte-identical rows). `Container.render` memoizes its concatenation on child references (children are still rendered every frame for their side effects); `Box` replaced its content-hashing cache with the same child-reference memo (no more per-frame `leftPad + line` rebuilds and full-content hashing); `Markdown`, `Spacer`, and `TruncatedText` return their cached arrays by reference instead of defensive copies. The TUI composes a persistent frame from per-child segments and an opt-in `RenderStablePrefix` report (consumable floor semantics for in-place mutators like the transcript), so marker extraction, line preparation (persistent prepared-frame replacing the per-frame rebuilt cache arrays), and the committed-prefix audit now run only over rows at/after the first changed row instead of every line of the transcript every frame
778
- - Rewrote the render core around an append-only native-scrollback contract. Committed rows are immutable: rows enter terminal history exactly once, in order, when the component-reported commit boundary (`NativeScrollbackLiveRegion`) marks them final, and the visible window repaints in place with relative moves. The engine no longer probes the terminal's scroll position or guesses whether a destructive rebuild is safe — the entire ED3-risk/defer/checkpoint machinery (viewport probes, eager streaming mode, dirty-scrollback reconciliation, deferred shrink/mutation intents, streaming high-water rebuilds, ConPTY-specific defer paths) is deleted. ED3 (`CSI 3 J`) now fires only on explicit user gestures: session replace, resize outside multiplexers, and `resetDisplay()`. This structurally removes the yank / flash / duplicated-rows / invisible-until-resize failure families tracked across #1610, #1635, #1651, #1682, #1719, #1746, #1799, #1823, #1962, #1974, #2000, #2011, #2154.
779
- - A frame that shrinks into its committed prefix re-anchors the visible window at the new tail and restarts commit bookkeeping; previously committed rows stay in history (history is never rewritten without a gesture).
780
- - Overlays now composite into the visible window slice only and freeze commits while visible, so overlay pixels can never enter native scrollback and closing an overlay no longer triggers a destructive history rebuild.
781
- - Inline-image budget demotion now deletes the demoted image's graphics by id and lets the window diff repaint the text fallback — no more mid-session destructive full replay when the image cap is exceeded.
782
- - The render-stress harness now validates the contract with a shadow commit ledger (an independent reimplementation of the ledger math fed only by observed frames and bytes), asserting scrollback equals the committed prefix row-for-row and that tape growth matches physical scroll exactly, across randomized op sequences, resizes, overlays, and multiplexer scenarios. The ghostty-web virtual terminal additionally survives libghostty-vt 0.4's WASM allocator traps via an event-log replay/compaction recovery, and strips non-spacing combining marks on input (a margin-aligned combining cluster deterministically corrupts that engine; mark placement through it was already unverifiable).
783
-
784
- ### Fixed
785
-
786
- - Fixed Windows rendering degrading into CP437 mojibake (`Γöé`/`ΓöÇ` instead of box-drawing borders and Nerd Font glyphs) after a console-sharing child process changed the console codepage (e.g. PHP CLI's implicit `chcp`, php.net request #73716): the breakage stayed latent until the next full repaint such as ctrl+o expand. The terminal now re-asserts the UTF-8 codepage (output and input) before each stdout write
787
- - Fixed crash recovery leaving the shell unusable: `emergencyTerminalRestore` (and `terminal.stop()`) never left the alt screen nor disabled mouse tracking, so a crash during a fullscreen overlay stranded the user on the alternate buffer with any-motion mouse reporting spewing escape garbage until a manual `reset`
788
- - Fixed bracketed paste with a lost `ESC[201~` end marker (ssh/tmux truncation) silently eating all subsequent input forever while growing memory unboundedly — paste mode now has an inactivity watchdog (1s) and a byte cap (64 MiB) that exit paste mode and deliver the accumulated bytes through the paste event
789
- - Fixed vertical cursor movement using UTF-16 code units as visual columns: Up/Down over emoji/CJK lines could land the cursor mid-surrogate-pair, rendering a lone surrogate and permanently corrupting the buffer on the next insert; movement now walks graphemes and snaps the target offset to a cluster boundary, also fixing column drift across wide glyphs
790
- - Fixed cursor positions inside whitespace trimmed at a word-wrap boundary mapping to no layout line — the cursor vanished and the viewport jumped to the buffer's last line; the preceding chunk now owns the skipped whitespace run
791
- - Fixed word-delete and kill-to-line operations (Ctrl+W/Alt+D/Ctrl+U/Ctrl+K) cutting through atomic paste markers, leaving `[Paste #1, +30` junk that no longer expanded to the pasted content on submit — delete ranges now extend over any atomic token they intersect
792
- - Fixed the kitty CSI-u printable dedup swallowing a real keystroke arbitrarily long after the duplicated event; the pending codepoint now expires after 25ms
793
- - Fixed `resetDisplay()` being a no-op on the alt screen: the redraw gesture could not repair a corrupted fullscreen modal because `#emitAltFrame` skipped identical-string repaints without consulting the force-repaint flag
794
- - Fixed the ghostty initial-image paint deferral consuming resize/cursor state before abandoning the frame, which could misclassify the deferred render's reflow and corrupt the paint — the deferral check now runs before any frame state is touched
795
- - Fixed the terminal-cursor inline-hint branch adding the full hint width to the line accounting even though the rendered hint was truncated, misaligning right padding whenever the hint overflowed
796
- - Fixed nested markdown list detection sniffing for hardcoded `\x1b[36m` (chalk cyan): every shipped theme emits truecolor/256-color SGR for bullets, so nested items doubled their indentation per level on all real themes; nesting is now tagged structurally by the list renderer. Ordered-list continuation lines also hang by the actual bullet width, so wrapped text under `10.`+ items aligns
797
- - Fixed committed transcript rows silently vanishing when a component re-laid-out content the engine had already scrolled into native history — a TTSR stream rewind truncating a streamed block, or the image budget demoting a committed inline image to its one-line fallback, shifted every row below by the height delta and the engine kept committing from the stale index, skipping that many rows of everything after (missing interruption banners, half-cut images in scrollback). The engine now audits its committed prefix every ordinary frame: an in-place edit or restyle keeps its alignment (stale styling in history remains the accepted artifact), while any shift re-anchors the commit index at the first moved row and recommits from there — history keeps the stale copy and gains a fresh one. Duplication, never loss. The detector (`findCommittedPrefixResync`, exported for the stress harness's shadow ledger) samples the prefix tail SGR-stripped so theme restyles and single-row edits never trigger spurious recommits.
798
- - Fixed budget-demoted inline images shrinking their transcript block: the text fallback is now height-preserving once a graphic has rendered (reserved rows plus the fallback line), so demotion never shifts content below a committed image.
799
- - Fixed stale trailing cells bleeding into committed history on combining-heavy rows: the native width model can over-count Arabic/combining clusters, classifying a short-rendering row as full-width and skipping the trailing erase — the previous occupant's cells then scrolled into scrollback baked into the committed row. Non-ASCII row rewrites now erase the line before writing.
800
-
801
- ### Removed
802
-
803
- - Removed the probe/defer API surface: `TUI.setEagerNativeScrollbackRebuild()`, `TUI.refreshNativeScrollbackIfDirty()`, `TUI.setClearOnShrink()`/`getClearOnShrink()`, `RenderRequestOptions.allowUnknownViewportMutation`, `NativeScrollbackRefreshOptions`, `Terminal.isNativeViewportAtBottom()`, `Terminal.hasEagerEraseScrollbackRisk()`, and the `eagerEraseScrollbackRisk`/`submitPinsViewportToTail` capability fields with their detectors.
804
- - Removed the `PI_TUI_ED3_SAFE`, `PI_CLEAR_ON_SHRINK`, and `PI_TUI_DEBUG` environment variables (the levers they tuned no longer exist; `PI_DEBUG_REDRAW` now logs the commit-ledger state per frame).
805
-
806
- ## [15.10.10] - 2026-06-09
807
-
808
- ### Fixed
809
-
810
- - Fixed committed transcript rows silently vanishing when a component re-laid-out content the engine had already scrolled into native history — a TTSR stream rewind truncating a streamed block, or the image budget demoting a committed inline image to its one-line fallback, shifted every row below by the height delta and the engine kept committing from the stale index, skipping that many rows of everything after (missing interruption banners, half-cut images in scrollback). The engine now audits its committed prefix every ordinary frame: an in-place edit or restyle keeps its alignment (stale styling in history remains the accepted artifact), while any shift re-anchors the commit index at the first moved row and recommits from there — history keeps the stale copy and gains a fresh one. Duplication, never loss. The detector (`findCommittedPrefixResync`, exported for the stress harness's shadow ledger) samples the prefix tail SGR-stripped so theme restyles and single-row edits never trigger spurious recommits.
811
- - Fixed budget-demoted inline images shrinking their transcript block: the text fallback is now height-preserving once a graphic has rendered (reserved rows plus the fallback line), so demotion never shifts content below a committed image.
812
- - Fixed stale trailing cells bleeding into committed history on combining-heavy rows: the native width model can over-count Arabic/combining clusters, classifying a short-rendering row as full-width and skipping the trailing erase — the previous occupant's cells then scrolled into scrollback baked into the committed row. Non-ASCII row rewrites now erase the line before writing.
813
-
814
- ### Changed
815
-
816
- - Rewrote the render core around an append-only native-scrollback contract. Committed rows are immutable: rows enter terminal history exactly once, in order, when the component-reported commit boundary (`NativeScrollbackLiveRegion`) marks them final, and the visible window repaints in place with relative moves. The engine no longer probes the terminal's scroll position or guesses whether a destructive rebuild is safe — the entire ED3-risk/defer/checkpoint machinery (viewport probes, eager streaming mode, dirty-scrollback reconciliation, deferred shrink/mutation intents, streaming high-water rebuilds, ConPTY-specific defer paths) is deleted. ED3 (`CSI 3 J`) now fires only on explicit user gestures: session replace, resize outside multiplexers, and `resetDisplay()`. This structurally removes the yank / flash / duplicated-rows / invisible-until-resize failure families tracked across #1610, #1635, #1651, #1682, #1719, #1746, #1799, #1823, #1962, #1974, #2000, #2011, #2154.
817
- - A frame that shrinks into its committed prefix re-anchors the visible window at the new tail and restarts commit bookkeeping; previously committed rows stay in history (history is never rewritten without a gesture).
818
- - Overlays now composite into the visible window slice only and freeze commits while visible, so overlay pixels can never enter native scrollback and closing an overlay no longer triggers a destructive history rebuild.
819
- - Inline-image budget demotion now deletes the demoted image's graphics by id and lets the window diff repaint the text fallback — no more mid-session destructive full replay when the image cap is exceeded.
820
- - The render-stress harness now validates the contract with a shadow commit ledger (an independent reimplementation of the ledger math fed only by observed frames and bytes), asserting scrollback equals the committed prefix row-for-row and that tape growth matches physical scroll exactly, across randomized op sequences, resizes, overlays, and multiplexer scenarios. The ghostty-web virtual terminal additionally survives libghostty-vt 0.4's WASM allocator traps via an event-log replay/compaction recovery, and strips non-spacing combining marks on input (a margin-aligned combining cluster deterministically corrupts that engine; mark placement through it was already unverifiable).
821
-
822
- ### Removed
823
-
824
- - Removed the probe/defer API surface: `TUI.setEagerNativeScrollbackRebuild()`, `TUI.refreshNativeScrollbackIfDirty()`, `TUI.setClearOnShrink()`/`getClearOnShrink()`, `RenderRequestOptions.allowUnknownViewportMutation`, `NativeScrollbackRefreshOptions`, `Terminal.isNativeViewportAtBottom()`, `Terminal.hasEagerEraseScrollbackRisk()`, and the `eagerEraseScrollbackRisk`/`submitPinsViewportToTail` capability fields with their detectors.
825
- - Removed the `PI_TUI_ED3_SAFE`, `PI_CLEAR_ON_SHRINK`, and `PI_TUI_DEBUG` environment variables (the levers they tuned no longer exist; `PI_DEBUG_REDRAW` now logs the commit-ledger state per frame).
826
-
827
- ## [15.10.9] - 2026-06-09
828
-
829
- ### Added
830
-
831
- - Added a `wrapDescription` option to `SelectListLayoutOptions`. When enabled, long descriptions wrap onto continuation rows indented under the description column instead of being silently truncated. The slash-command/skill autocomplete picker now opts in so descriptions like the bundled skills' remain fully readable at normal terminal widths. `maxVisible` becomes the picker's visual row budget so the popup height stays bounded even when items wrap (a single 5-row description with `maxVisible=3` clips with the scrollbar carrying the offscreen tail). Navigation stays item-to-item, the narrow-width fallback (`width <= 40`) is unchanged, and the `ScrollView` scrollbar tracks visual rows so the thumb stays correct when items wrap unevenly. ([#2169](https://github.com/can1357/oh-my-pi/issues/2169))
832
-
833
- ### Fixed
834
-
835
- - Fixed Ghostty's first inline image in a fresh TUI session sometimes rendering as an empty placeholder block by holding the initial Kitty graphics paint until the terminal startup settle window has passed. Direct Kitty placements also keep their zero-width reservation rows non-plain so image-only transcript blocks do not collapse when blank-edge trimming runs.
836
-
837
- ## [15.10.8] - 2026-06-09
838
-
839
- ### Fixed
840
-
841
- - Fixed TUI renders repeatedly clearing terminal scrollback after content filled the viewport. Unknown viewport probes no longer let foreground-streaming offscreen growth take the destructive `historyRebuild` path on every frame; newly appended tail rows stay reachable while stale history waits for a safe checkpoint. ([#2154](https://github.com/can1357/oh-my-pi/issues/2154))
842
-
843
- ## [15.10.6] - 2026-06-08
844
-
845
- ### Added
846
-
847
- - Added `TUI.getFocused()` accessor and `Input.pasteText(text)` method so callers consuming non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard) can route a paste payload to the currently focused modal Input rather than always to the primary editor. Mirrors the existing `Editor.pasteText` semantics: newlines stripped, tabs normalized, NFC normalization applied. ([#2127](https://github.com/can1357/oh-my-pi/issues/2127))
848
-
849
- ### Fixed
850
-
851
- - Fixed tmux/screen/zellij rewind/branch (`requestRender(true, { clearScrollback: true })`) permanently anchoring the input box to the pane top and overlaying scrollback after a streamed reply had grown past the viewport. `#emitFullPaint` only reset `#scrollbackHighWater` inside the `clearScrollback` branch and otherwise raised it monotonically, so inside multiplexers (where `\x1b[3J` is a no-op and `clearScrollback` is forced off) the streaming peak survived the rewind; on the next frame `#planLiveRegionPinnedRender` saw the stale high-water and anchored `renderViewportTop` past the actual content, repainting every visible row blank and parking the cursor at screen row 0 for the rest of the session. A full repaint with `clearViewport: true` re-emits the entire transcript from row 0, so `#scrollbackHighWater` is now assigned (not max-clamped) to the natural push count regardless of whether ED 3 was issued ([#2130](https://github.com/can1357/oh-my-pi/issues/2130)).
852
-
853
- ## [15.10.5] - 2026-06-08
854
-
855
- ### Added
856
-
857
- - Added `atomicTokenPattern` to `Editor`: when set to a global regex matching placeholder tokens such as `[Image #1, 800x600]` or `[Paste #2, +30 lines]`, a single backspace or forward-delete landing anywhere on a token removes the whole token instead of corrupting it into stray text.
858
-
859
- ### Changed
860
-
861
- - Changed the large-paste placeholder label from `[paste #N +X lines]`/`[paste #N Y chars]` to `[Paste #N, +X lines]`/`[Paste #N, Y chars]`.
862
-
863
- ### Fixed
864
-
865
- - Fixed pasting large text lagging the prompt for hundreds of milliseconds before the `[paste #N …]` placeholder appeared. `StdinBuffer` assembled bracketed pastes by re-concatenating and re-scanning the entire accumulated buffer on every incoming stdin chunk (`#pasteBuffer += chunk; indexOf(END)`), which is O(n²) in the paste size and dominates when the terminal/PTY delivers the paste in many small reads (SSH, tmux, slow hosts) — a 1 MB paste at 1 KB chunks cost ~33 ms and 5 MB ~740 ms. Chunks are now collected in an array and joined once when the end marker arrives, with a short overlap tail carried across chunk boundaries so a marker split between two reads is still detected without rescanning, making assembly O(n) (~1 ms for 5 MB). The `Editor` paste cleaner also dropped its `split("").filter().join("")` per-code-unit array allocation in favor of a single control-character regex pass (~20× faster on large pastes).
866
-
867
- ## [15.10.4] - 2026-06-08
868
-
869
- ### Fixed
870
-
871
- - Fixed Windows ConPTY session-resume painting the transcript with the last several rows truncated below the viewport until Alt+Tab forced a host repaint. After `sessionReplace`/`historyRebuild`/`overlayRebuild` paints that scroll-push content into native scrollback, the renderer now arms a 150 ms ConPTY settle window that coalesces spinner/blink-driven `requestRender(false)` calls into a single trailing render — Windows Terminal's viewport-follow logic no longer falls further behind the cursor on every tick of the post-paint storm. The arm also reclaims any render request queued *during* the in-flight composition (notably `ImageBudget.endPass()` calling `requestRender()` synchronously when a frame trips the live-graphics cap): without that, the queued request sat on the standard 30 Hz throttle and fired at ~33 ms — well inside the 150 ms quiet window — defeating the coalescing. Bumped the ConPTY per-`WriteFile` chunk cap from 8 KiB to 16 KiB so a multi-megabyte resume paint emits half as many writes (still well under the ~32 KiB threshold from #2034 that the original cap defends against), and made the cap measure encoded UTF-8 bytes instead of JS code units so a CJK-heavy transcript can't silently inflate a 16-KiB-of-code-units chunk into ~48 KiB of `WriteFile` traffic and reintroduce the #2034 viewport bug ([#2095](https://github.com/can1357/oh-my-pi/issues/2095)).
872
-
873
- ## [15.10.3] - 2026-06-08
874
-
875
- ### Fixed
876
-
877
- - Fixed DEC 2048 in-band resize reports (`CSI 48;rows;cols;hpx;wpx t`) leaking into the focused editor as literal text during a rapid resize. When the window is resized quickly the event loop stays busy long enough for the `StdinBuffer` flush timeout to fire mid-report; the `\x1b[48;…` prefix was emitted as one event and the tail (e.g. `8;125;1156;1125t`) arrived as bare printable characters that the editor inserted. `ProcessTerminal` now reassembles a split in-band report (including a split at the bare `\x1b[4` type field) until its terminator and then drives the resize. A reassembled sequence that turns out not to be a resize report — such as a split kitty key like `\x1b[48;5u` (codepoint 48 = `0`) — is forwarded to the input handler as a single escape sequence rather than dropped or leaked.
878
- - Coalesced terminal-multiplexer SIGWINCH events into a single forced render once the pane stops resizing so closing/dragging a tmux/screen/zellij split no longer flashes the viewport blank before the new geometry repaints ([#2088](https://github.com/can1357/oh-my-pi/issues/2088)).
879
-
880
- ## [15.10.2] - 2026-06-08
881
-
882
- ### Added
883
-
884
- - Added exported `canonicalKeyId` and `addKeyAliases` keybinding helpers so consumers can share the same canonical shortcut matching semantics as `KeybindingsManager`.
885
- - Added `super` modifier support to native key parsing/matching and bound `super+alt+backspace` / `super+alt+delete` (and `super+alt+d`) into the word-delete defaults so Ghostty's default macOS Option+Backspace wire (`ESC [127;11u` — kitty modifier 11 = super|alt) deletes a word instead of falling through to single-char delete ([#2064](https://github.com/can1357/oh-my-pi/issues/2064)).
886
-
887
- ### Fixed
888
-
889
- - Fixed focus-changing in-place menus leaving stale Working/menu rows and parking the hardware cursor in the old menu viewport on terminals without a scroll-position oracle.
890
- - Fixed redundant terminal cursor updates so repeated renders that do not change the cursor row, column, or visibility no longer emit ANSI move/hide sequences
891
- - Fixed repeated cursor updates during no-op re-renders by reusing the last known cursor state, preventing unnecessary cursor position changes and hide/show sequences
892
- - Fixed the kitty keyboard progressive-enhancement probe to honor the `CSI ? <flags> u` reply even when the terminal answers the DA1 sentinel first. Previously the kitty reply was discarded once the DA1-driven `modifyOtherKeys` fallback engaged, so terminals like Superset/xterm-on-Electron stayed on the fallback and delivered Shift+Enter as a bare `\r` ([#2042](https://github.com/can1357/oh-my-pi/issues/2042)).
893
- - Bounded TUI line fitting for oversized raw rows so ANSI-heavy subagent output and zero-width-heavy text cannot grow render buffers independently of the viewport or hide visible suffix text ([#2045](https://github.com/can1357/oh-my-pi/issues/2045)).
894
- - Fixed tmux offscreen-shrink frames to skip repainting when the visible tail is unchanged, avoiding intermittent blank/refresh flashes in pane terminals ([#2046](https://github.com/can1357/oh-my-pi/issues/2046)).
895
- - Fixed Windows ConPTY hosts (Windows Terminal, Tabby, Hyper, VS Code) parking the viewport at the top of a full paint after a `/resume` or any long-session repaint. `ProcessTerminal#safeWrite` now splits oversized writes into ≤ 8 KiB pieces at line boundaries on `win32` and inside WSL (where stdout still crosses ConPTY at the `wslhost` boundary) so each underlying `WriteFile` stays below the ~32 KiB threshold where ConPTY stops tracking the cursor; the data was always delivered, but the host UI's scroll position would not follow until any focus event forced a re-query. ([#2034](https://github.com/can1357/oh-my-pi/issues/2034))
896
-
897
- ## [15.10.1] - 2026-06-07
898
-
899
- ### Breaking Changes
900
-
901
- - Removed Kitty temp-file image transmission, its startup support probe, the `PI_KITTY_IMAGE_TRANSMISSION` override, and the temp-file helper exports. Kitty/Ghostty image payloads now stay on in-band base64 before placeholder/direct placement, avoiding blank first renders from temp-file load races.
902
- - Renamed `RenderRequestOptions.allowUnknownViewportMutation` → `allowUnknownViewportTransientRepaint`. The option only permits a transient live-viewport repaint (autocomplete/IME/focused-editor chrome) on hosts that cannot report viewport position; it never authorizes a settled transcript commit. The old name implied any offscreen mutation was safe to push into native scrollback, which led callers to emit duplicate transcript copies.
903
-
904
- ### Added
905
-
906
- - Added `TUI.addStartListener()` so feature hooks can re-enable terminal modes after temporary stop/start cycles such as external-editor handoffs.
907
- - Added `Editor.pasteText()` to apply terminal-style paste handling for text inserted from non-bracketed paste transports
908
- - Added an optional `dispose()` lifecycle method to `Component` so components can release timers and subscriptions during permanent teardown
909
- - Added `Container.dispose()` to propagate teardown to child components when a component tree is permanently discarded
910
- - Added `Loader.dispose()` to stop the loader animation timer when the component is disposed
911
- - Added a `ScrollView` `ellipsis` option (defaults to `Ellipsis.Unicode`) so callers that pre-wrap content to width can pass `Ellipsis.Omit` and suppress the stray per-line `…` that lands on trailing padding.
912
- - Added `ScrollView.handleScrollKey()` plus a `fastScrollLines` option so every scroll view gets shared navigation keys, including Shift+Arrow to scroll faster.
913
- - Added `OverlayOptions.fullscreen`: while the topmost visible overlay sets it, the engine borrows the terminal's alternate screen buffer for the overlay's lifetime and paints only the modal there — no ED3, no transcript re-commit — so the transcript stays untouched on the normal screen and is not scrollable behind the modal. Mouse tracking (`?1000h`/`?1006h`) is enabled for the modal's lifetime and disabled on exit, so the rest of the app keeps the terminal's native text selection.
914
- - Added the `submitPinsViewportToTail` terminal capability and `detectSubmitPinsViewportToTail()`: genuine local terminals where a submit keystroke scrolls the host to its tail reconcile deferred native scrollback at the prompt-submit checkpoint even when the viewport position is unprobeable (Ghostty/kitty/iTerm/WezTerm/Alacritty). Restores the pre-regression submit reconciliation without re-enabling it for Windows Terminal/ConPTY, SSH, or multiplexers, where a submit is not proof the host is at the tail.
915
-
916
- ### Changed
917
-
918
- - Changed static `Loader` messages to repaint only at the spinner's 80 ms cadence; time-dependent message colorizers can opt into 16 ms redraws with `animated: true`.
919
- - Changed keybinding matching to precompute canonical key sets so each input sequence is parsed once per binding check instead of once per candidate key.
920
- - Made `Component.invalidate()` optional so leaf components without render caches no longer need no-op invalidation hooks.
921
- - `TERMINAL` is now a `RuntimeTerminal` whose post-construction capabilities (image protocol and the probe-driven flags) are writable, replacing the `as unknown as MutableTerminalInfo` cast pattern and the positional `withTerminalOverrides` rebuild with a prototype-preserving `clone()`.
922
-
923
- ### Fixed
924
-
925
- - Fixed `Loader` text updates to skip identical messages and preserve the rendered `Text` cache instead of invalidating it every timer tick.
926
- - Fixed fullscreen overlay alt-frame rendering to reuse the current line-preparation path instead of calling removed fitting helpers.
927
- - Reduced TUI render-path line fitting by deferring overlay base-frame fitting until an overlay rebuild and by reusing already-fitted lines in emitters.
928
- - Reduced live-region pinned repaint output by diffing unchanged viewport rows when no sealed rows are being committed to native scrollback.
929
- - Fixed no-append live-region pinned repaints to re-anchor the hardware cursor when the logical viewport shifts.
930
- - Fixed keybinding matching so printable uppercase input preserves `Shift` for bindings such as `shift+a`.
931
- - Optimized terminal image-line detection and Thai/Lao AM normalization checks to avoid hot-path regex scans and substring allocations.
932
- - Fixed `Markdown.render()` cache hits returning the cache's mutable backing array, which let callers that append extra rows corrupt cached Markdown and duplicate those rows on every redraw.
933
- - Fixed first-paint full replays for callers that intentionally replace terminal history by allowing `TUI.start({ clearScrollback: true })`, so they do not briefly append an entire initial frame before the first clean replay.
934
- - Fixed ED3-risk streaming cap accounting to preserve the native scrollback high-water mark for rows that were already physically committed before transient frames were viewport-capped.
935
- - Fixed terminal stop and restore cleanup to disable enhanced paste mode so it does not remain enabled after shutdown
936
- - Removed the per-frame line-fit `Map` cache from the render timer path to avoid forcing JSC rope-string hashing during scheduled viewport repaints.
937
- - Fixed `visibleWidth()` so terminal column measurements for ANSI and OSC text now match the native truncation/wrapping helpers, including OSC 66 text-sizing spans being counted at their scaled payload width
938
- - Fixed cursor, padding, and line-fit behavior when strings contain tabs or OSC escapes by aligning `visibleWidth()` with the native text-width model
939
- - Fixed the transcript — or a re-appearing prior view such as the welcome screen — duplicating itself on terminals without a scroll-position oracle (Ghostty/kitty/iTerm/WezTerm) when a foreground tool completes by rewriting a partly-committed block, or when the transcript is reset. A non-destructive viewport repaint no longer re-paints rows that are byte-identical to what is already committed to native scrollback into the active grid; the repaint anchor is clamped to the committed-and-unchanged prefix (`min(firstChanged, scrollbackHighWater)`).
940
-
941
- ## [15.10.0] - 2026-06-06
942
-
943
- ### Changed
944
-
945
- - Reworked the DEC 2026 synchronized-output default policy: a positive DECRQM mode-2026 report now **enables** sync (previously a report could only disable it), so conservatively defaulted-off hosts that actually support it — current Zellij, tmux master, foot, contour, mintty — are upgraded at runtime. The static allowlist also covers Alacritty and the VS Code terminal, honors a `TERM_FEATURES` `Sy` advertisement and `WT_SESSION` (Windows Terminal / WSL), and no longer blanket-disables SSH (DEC 2026 passes through to the outer terminal). Risky multiplexers still start off and rely on the probe. Added `synchronizedOutputUserOverride()` as the shared opt-out/force resolver.
946
-
947
- ### Fixed
948
-
949
- - Fixed WSL/Windows Terminal row flicker while typing by repainting changed text rows before clearing only their stale suffix ([#2011](https://github.com/can1357/oh-my-pi/issues/2011)).
950
- - Fixed terminals that support DEC 2026 still tearing/flickering because the renderer ignored a positive DECRQM capability report and kept synchronized output off — most visibly WSL + Windows Terminal, Alacritty (≥0.13), and the VS Code terminal (≥1.108), which were detected yet refused sync.
951
-
952
- ## [15.9.69] - 2026-06-06
953
-
954
- ### Added
955
-
956
- - Added `TUI.resetDisplay()` to force an immediate full-frame replay, including native scrollback when the host can safely clear it.
957
- - Added `setPaddingY` to `Box` so vertical padding can be updated programmatically after creation.
958
-
959
- ### Fixed
960
-
961
- - Fixed DECCARA background-fill optimization running when synchronized output is disabled, which could expose default-background gaps during rapidly updating tool-use panels ([#2000](https://github.com/can1357/oh-my-pi/issues/2000)).
962
-
963
- ## [15.9.67] - 2026-06-06
964
-
965
- ### Added
966
-
967
- - Added `setPaddingX` to `Box` so horizontal padding can be updated programmatically after creation
968
- - Added `ScrollView`, a fixed-height viewport component for pre-rendered lines with optional right-edge scrollbars and imperative scroll/page controls.
969
- - Added optional `Terminal.hasEagerEraseScrollbackRisk()` so custom/test terminal implementations can override the global ED3-risk profile without mutating the shared `TERMINAL` object.
970
-
971
- ### Changed
972
-
973
- - Changed `SelectList` to render its visible window through `ScrollView`, replacing the `(N/M)` text scroll indicator with a uniform right-edge scrollbar (the type-to-search hint line is preserved).
974
-
975
- ### Fixed
976
-
977
- - Fixed unknown-viewport deferred renders freezing bottom-anchored live chrome; deferred history mutations can now repaint only the active-grid bottom row with relative cursor movement, so spinner/status tails keep advancing without rewriting rows a scrolled reader can still see.
978
- - Fixed autocomplete popups freezing live repaint on ED3-risk macOS/POSIX terminals with unknown native viewport position; direct autocomplete shrink frames now repaint the live viewport without zero-byte deferral and preserve the old bottom anchor when padding can clear stale popup rows without duplicating committed scrollback.
979
- - Fixed focused Up/Down navigation on ED3-risk macOS/POSIX terminals replaying the whole transcript after dirty foreground-stream renders; selector/editor frames now repaint non-destructively instead of emitting `CSI 3 J` on every arrow-key move ([#1962](https://github.com/can1357/oh-my-pi/issues/1962)).
980
- - Fixed tmux (and screen/zellij) pane scrollback losing the head of a long streamed assistant reply once it grew past the visible pane, and stranding the chrome/footer in pane history after a later collapse — producing the "repeating chunks and missing sections" reporters saw when scrolling back through tmux pane history ([#1974](https://github.com/can1357/oh-my-pi/issues/1974)). The renderer's foreground-streaming cap-to-viewport branch (introduced in 15.9.2 for ED3-risk hosts that can checkpoint-rebuild later) also activated inside multiplexers, where checkpoint reconcile is a no-op (`refreshNativeScrollbackIfDirty` short-circuits because `\x1b[3J` cannot erase pane history). Every streaming frame clipped `lines` to the visible tail and reset `#scrollbackHighWater` to 0, so any row that scrolled above the viewport top was committed nowhere — pane history stayed empty until streaming ended. Meanwhile `#planLiveRegionPinnedRender` was explicitly disabled for multiplexers, but its `#emitLiveRegionPinnedRepaint` is built from the exact primitives tmux accepts (relative cursor moves, per-line `\x1b[2K`, `\r\n` to scroll the sealed prefix past the viewport bottom) and never emits `\x1b[2J`/`\x1b[3J`. The pinned planner now runs in multiplexers too, the cap branch skips them, and the diff/append path commits incrementally into pane history; the actively-mutating live tail stays in the visible viewport only.
981
-
982
- ## [15.9.5] - 2026-06-05
983
-
984
- ### Changed
985
-
986
- - Changed terminal resize handling so any width or height change always performs a clean reset + redraw: the renderer now unconditionally clears the viewport and native scrollback (`CSI 2 J` / `CSI 3 J`) and replays the full transcript at the new geometry, replacing the previous matrix of conditional viewport-repaint / history-rebuild / deferred-mutation branches. Multiplexer panes still repaint the visible window in place (pane scrollback cannot be erased), but a resize during active ED3-risk foreground streaming now performs the same clean rebuild rather than downgrading to a non-destructive viewport repaint: the terminal already re-wrapped its saved lines at the old width, so the rebuild must erase them (ED 3) instead of leaving the mis-wrapped history on screen. As a deliberate tradeoff this drops the prior no-overflow and confirmed-scrolled guards on resize: a reader scrolled into history snaps back to the bottom and preexisting shell scrollback above the UI is cleared.
987
-
988
- ### Fixed
989
-
990
- - Fixed ED3-risk foreground streaming dropping the scrolled-off head of an append-only live block that alone overflows the viewport (a long streamed assistant reply). The live-region pin again committed native scrollback only up to the live-region start, so once the live block grew past the viewport its earlier rows scrolled above the viewport top but were committed nowhere and repainted nowhere — they vanished, leaving the reply looking like a ~viewport-tall circular buffer. The `NativeScrollbackLiveRegion` seam now also reports an optional append-only `getNativeScrollbackCommitSafeEnd`, and the pinned commit boundary is the deeper of the sealed start and that append-only end: rows in `[liveRegionStart, commitSafeEnd)` above the viewport top commit to scrollback, while volatile live blocks (tool previews that collapse) omit the boundary and keep their mutable rows deferred — preserving the pending-box-above-running-box fix.
991
-
992
- ## [15.9.4] - 2026-06-05
993
-
994
- ### Added
995
-
996
- - Added `PI_TUI_SYNC_OUTPUT=0` and `PI_TUI_SYNC_OUTPUT=1` to explicitly disable or force-enable DEC 2026 synchronized-output mode, alongside `PI_FORCE_SYNC_OUTPUT=1` as a force-on alias
997
- - Added `PI_TUI_ED3_SAFE=1` environment override to treat a terminal as non-ED3-risk for eager native scrollback rebuilds on unknown POSIX hosts
998
-
999
- ### Changed
1000
-
1001
- - Changed native-scrollback safety defaults to treat unknown POSIX, SSH, and multiplexer-shaped terminals as ED3-risk for passive rendering; checkpoint replay now requires a positive at-tail viewport proof instead of assuming prompt submit makes host scrollback safe.
1002
- - Changed synchronized-output defaults to a conservative opt-in profile: DEC 2026 paint wrappers stay disabled for remote/multiplexer/VTE/unknown terminals unless explicitly forced, while the autowrap guards remain active.
1003
-
1004
- ### Fixed
1005
-
1006
- - Fixed ED3-risk unknown-viewport renders repainting offscreen structural edits over stale native scrollback, which could duplicate or shift rows when async blocks collapsed or middle rows were deleted.
1007
- - Fixed ED3-risk foreground streams committing mutable live-region rows into native scrollback, which could leave a stale `pending` tool box above the `running` box after the preview re-rendered.
1008
- - Fixed TUI shutdown leaving paint-time terminal state and Kitty image data behind by restoring synchronized-output/autowrap modes and purging all transmitted Kitty image ids on stop.
1009
- - Fixed stdin buffering splitting surrogate-pair text into UTF-16 halves and reduced timing sensitivity for incomplete escape sequences.
1010
- - Fixed terminal content not reflowing after a resize on terminals using DEC 2048 in-band resize (kitty/Ghostty/iTerm2/WezTerm). `ProcessTerminal.columns`/`rows` returned the last cached in-band report even after the OS already knew the new size, so a SIGWINCH whose in-band report was dropped or malformed (split past the stdin flush window, `:`-subparameter fields) re-rendered the whole transcript at the stale width. OS resize events now reconcile cached in-band geometry against the live `process.stdout` dimensions, dropping a stale cached value so the next render uses the true size; a valid in-band report still re-seeds pixel sizing.
1011
-
1012
- ## [15.9.3] - 2026-06-05
1013
-
1014
- ### Fixed
1015
-
1016
- - Fixed ED3-risk foreground streaming erasing the head of any block that alone overflows the viewport (a tall tool result drawn in one frame, or a multi-line assistant reply growing past the viewport as it streams). The live-region pin committed native scrollback only up to the sealed-prefix boundary (`liveRegionStart`), so rows of the live block that had physically scrolled above the viewport top were neither pushed into scrollback nor kept in the repainted viewport — they vanished. The commit boundary is now the viewport top: every row above the viewport enters scrollback (only the tail still visible in the viewport stays transient and deferred to the checkpoint).
1017
- - Fixed the same ED3-risk live-region pin duplicating already-committed scrollback rows when a foreground stream's live region collapsed mid-turn (a tool preview shrinking to its compact result, an assistant block re-wrapping shorter, a late tool completion). Because growth commits every row above the viewport top to native scrollback, a subsequent shrink moved the bottom-anchored viewport back across those committed rows and the repaint re-drew them into the viewport — so they appeared twice on scroll-up, and with no prompt-submit checkpoint to reconcile (autonomous multi-turn runs, or the session ending into the welcome screen) the duplicate was baked permanently into terminal history. The pinned repaint now separates commit geometry from repaint geometry: a collapse clamps the repaint to the committed sealed boundary (`min(#scrollbackHighWater, liveRegionStart)`) instead of re-exposing those rows, leaving native scrollback un-duplicated without emitting ED3 under a possibly-scrolled reader; stale mutable live-region saved lines still reconcile at the next checkpoint.
1018
- - Fixed hiding overlays during ED3-risk foreground streaming on unknown-viewport terminals leaving the overlay's transient rows in native scrollback. Overlay visibility reductions now bypass the streaming deferral path and rebuild once, so hidden dialog/notification sentinels are scrubbed immediately.
1019
- - Fixed ED3-risk / unknown-viewport terminals (including WSL fronted by Windows Terminal) keeping the foreground-stream eager-rebuild mode active after the stream had already settled. A later scrolled content shrink or resize-with-append could then bypass the anti-yank deferral and repaint from stale geometry, jumping the viewport or replaying the wrong rows. The eager opt-in now drops immediately when no teardown render is pending, and the one-frame post-checkpoint suffix-suppression path no longer overrides geometry reflow handling.
1020
-
1021
- ## [15.9.2] - 2026-06-05
1022
-
1023
- ### Changed
1024
-
1025
- - Changed foreground-stream rendering on ED3-risk terminals (Ghostty/kitty/Alacritty/VTE/iTerm2 on POSIX) to defer native-scrollback commits for unpinned transient frames: while a turn streams, generic frames repaint only the viewport and suppress `\r\n` scroll growth, so transient output (spinner ticks, partial lines, status rows) never pollutes terminal history. Components that report a `NativeScrollbackLiveRegion` still commit newly sealed prefix rows while keeping the active suffix dirty for checkpoint replay. Native scrollback is reconciled in a single ED3 (`CSI 3 J`) + re-emit at the next checkpoint (prompt submit) or on an explicit user-input/IME opt-in; an erase is never emitted mid-stream under a possibly-scrolled reader. Non-ED3-risk terminals keep their eager live rebuild. ([#1895](https://github.com/can1357/oh-my-pi/pull/1895))
1026
-
1027
- ### Fixed
1028
-
1029
- - Fixed ED3-risk foreground streaming dropping sealed transcript rows above the live block until the next prompt-submit checkpoint, which made scrollback beyond the viewport appear duplicated or out of order. The renderer restores native-scrollback live-region pinning so newly sealed rows are appended once while active live rows remain deferred.
1030
- - Fixed inline images (added in 15.9) rendering as a wall of empty PUA box glyphs and producing laggy scrolling on Kitty-protocol terminals that do not implement Unicode placeholders — most notably WezTerm (per upstream wezterm/wezterm#986, placeholder support is still unchecked) and the tmux/screen `getFallbackImageProtocol` path that forces Kitty mode even on non-supporting outer terminals (Terminal.app, etc.). `unicodePlaceholders` now defaults on only for `kitty` and `ghostty`; everything else falls back to direct `a=p,i=…,p=…` placement, which those paths already render correctly. `PI_NO_KITTY_PLACEHOLDERS=1` is still honored as a hard opt-out, and a new `PI_KITTY_PLACEHOLDERS=1` opts in on otherwise-unsupported terminals (e.g. a wezterm nightly that has merged placeholder support) ([#1877](https://github.com/can1357/oh-my-pi/issues/1877)).
1031
-
1032
- ## [15.9.1] - 2026-06-04
1033
-
1034
- ### Fixed
1035
-
1036
- - Fixed the OSC 11 appearance poll re-querying every 2s forever on terminals that support Mode 2031 but never change theme, whose repeated OSC 11/DA1 writes cleared the user's active text selection (breaking copy every 2 seconds). The poll now stops as soon as DECRQM confirms Mode 2031 support, since push notifications make polling redundant.
1037
-
1038
- ## [15.9.0] - 2026-06-04
1039
-
1040
- ### Added
1041
-
1042
- - Added Kitty `CSI 22 J` screen-to-scrollback clears for non-destructive full paints, while keeping ED3 for destructive history/session rebuilds.
1043
- - Added Kitty OSC 99 rich notification formatting and startup capability probing.
1044
- - Added Kitty OSC 66 text-sized Markdown H1 headings (2x scale) plus native text-width support for OSC 66 spans. Off by default and gated to Kitty (the only terminal implementing OSC 66) via the `TERMINAL.textSizing` capability; hosts enable it through `setTextSizing`.
1045
- - Added Kitty Unicode placeholder image rendering (`U=1` + U+10EEEE with explicit row/column diacritics): inline images are drawn as real text cells that carry the image id in their foreground color, so they survive horizontal slicing, reflow, and overlapping draws instead of relying on cursor-positioned `a=p` placements. Enabled by default on Kitty-family terminals; opt out with `PI_NO_KITTY_PLACEHOLDERS=1`, and falls back to direct placement when a grid exceeds the diacritic table's addressable range.
1046
- - Added Kitty temp-file image transmission (`t=t`): on local sessions, decoded PNG bytes are written to a `tty-graphics-protocol` temp file and the path is sent instead of in-band base64, gated behind a startup `a=q,t=t` support probe. Controlled by `PI_KITTY_IMAGE_TRANSMISSION=direct|temp-file|auto`; disabled over SSH unless explicitly forced.
1047
- - Added DECRQM capability detection for DEC private modes 2026 (synchronized output) and 2048 (in-band resize). Synchronized-output paint wrappers are dropped when the terminal reports 2026 unsupported (preserving the `PI_NO_SYNC_OUTPUT` override), and DEC 2048 in-band resize is enabled when supported — reported geometry and cell pixel size are updated from `CSI 48 ; rows ; cols ; yPx ; xPx t` reports, with SIGWINCH and `CSI 16 t` kept as fallbacks.
1048
- - Added an injectable render scheduler for TUI tests, allowing deterministic render drains without patching global clocks or event-loop timing.
1049
- - Added `ImageBudget`, an inline-image cap that keeps only the most recent N images as live terminal graphics and demotes older ones to their text fallback. Once a new image pushes the count past the cap, the renderer hides the oldest via a full redraw plus an explicit Kitty graphics purge (`a=d,d=I`) — text-clear escapes (`CSI 2 J`/`CSI 3 J`) do not remove Kitty images. Configure the cap via `TUI#setMaxInlineImages` (`0` disables it).
1050
- - Changed Kitty inline images to a transmit-once + placement scheme: the base64 data is sent a single time (`a=t`) keyed by a stable image id, then every repaint emits only the tiny placement (`a=p,i=…,p=…`). Repaints — including full redraws — no longer re-send image data or stack duplicate placements, and the diff/line buffers and render caches hold short placement strings instead of multi-KB base64. The `ImageBudget` doubles as the transmit store (it tracks which ids are loaded and re-transmits after a purge frees the data). iTerm2/Sixel, which have no addressable image store, keep sending inline data as before.
1051
- - Added a renderer-level DECCARA rectangular-SGR optimizer that paints solid background panels/rows (Box/Text/Markdown fills, status bars, any full-width `theme.bg` row) as a single coalesced rectangle escape (`CSI 2*x` / `CSI Pt;Pl;Pb;Pr;<sgr>$r` / `CSI *x`) instead of emitting a full-width run of background-styled spaces on every visible row. It operates at emit time on the final ANSI strings — components are unchanged — and strips only trailing padding it can prove sits under a single non-default background span, coalescing vertically adjacent identical fills into one rectangle and falling back to the original bytes whenever the rectangle would not save bytes. Enabled only on Kitty, which implements the SGR-background extension (`docs/deccara.rst`); **Ghostty is intentionally excluded** because its `CSI $r` is unimplemented (ghostty-org/ghostty#632) and would drop the background entirely. Scrollback-bound rows and the append/scroll paths always keep the padded representation so native history preserves colored cells, and the `PI_NO_DECCARA` kill switch (plus tmux/screen/zellij detection) forces the fallback.
1052
- - Added `CMUX_SURFACE_ID` environment variable support to `getTerminalId()`, so cmux terminal surfaces get a stable identifier alongside kitty, tmux, macOS Terminal.app, and Windows Terminal — enabling per-surface session breadcrumbs for `omp -c` in cmux.
1053
-
1054
- ### Changed
1055
-
1056
- - Changed TUI tests to use Ghostty's VT engine (`ghostty-web`) instead of `@xterm/headless`.
1057
- - Changed the default inline-image live graphics budget from 3 to 8 images.
1058
-
1059
- ### Fixed
1060
-
1061
- - Fixed the DECCARA background-fill optimizer rejecting or repainting the wrong cells when a trailing fill crossed from default-background spaces into colored spaces.
1062
- - Fixed DEC private-mode reports with DECRPM status 3/4 being treated as unsupported, so permanent 2026/2048 reports stay recognized.
1063
- - Fixed OSC 66 text-sizing width and slicing edge cases, including ZWJ emoji payloads and partial slices through scaled spans.
1064
- - Fixed focused `Input` components following `TUI#setShowHardwareCursor`, so single-line prompts render either the terminal cursor or software cursor consistently with the editor.
1065
- - Fixed the DECCARA background-fill optimizer painting fills on the wrong rows ("split into unaligned halves") in the differential repaint path. When a diff grew the transcript past the viewport, writing the rewritten rows scrolled the terminal, but the absolute DECCARA rectangle coordinates were derived from the pre-scroll viewport top, so every fill landed `scrollAmount` rows too low while the relatively-positioned text settled correctly; rows scrolled into history were also shortened, dropping their background padding from native scrollback. Rectangles now target the post-scroll rows and only rows remaining in the final viewport are optimized.
1066
- - Fixed native scrollback desynchronization after terminal width or height changes reflowed overflowing content while the viewport was not at the bottom
1067
- - Fixed a notification chip (or any injected block) rendering on top of an actively streaming tool render on ED3-risk terminals (Ghostty/kitty/Alacritty/iTerm2). While a foreground tool streams, its header's elapsed-time counter ticks every frame; once output scrolls the header above the viewport top, each tick is an offscreen edit that — because the eager scrollback-rebuild opt-in is gated off on these terminals — repaints the viewport in place and advances the rendered line count without committing the new overflow to native history. `#scrollbackHighWater` then lagged the logical viewport top, so a later content shrink whose changes landed in the visible region slipped past the shrink-across-boundary guard and reached the differential emitter, which is anchored to `#maxLinesRendered - height`: it rewrote only the suffix, dropped the newly exposed top row, and left a blank at the bottom, drifting every row below the edit one line up so it painted over the rows above. Such shrinks now re-anchor the bottom of the viewport with a non-destructive repaint, and the foreground-streaming shrink-across-boundary case repaints the live tail instead of padding and pinning the pre-shrink viewport.
1068
- - Fixed a terminal resize during foreground-tool streaming on an unknown-viewport / ED3-risk host (Ghostty/kitty/Alacritty/iTerm2/WSL) leaving native scrollback permanently out of sync, so scrolling back after the turn showed missing rows. A pure geometry resize (no content change) takes the in-place viewport-repaint path, which — unlike a content-bearing resize that rebuilds via the geometry branch — never flagged native history. Because the prompt-submit checkpoint (`refreshNativeScrollbackIfDirty`) only rebuilds when scrollback is marked dirty on these hosts, the discrepancy was never reconciled. Overflowing geometry repaints whose viewport is not known to be at the bottom now mark scrollback dirty so the next checkpoint rebuilds an exact copy of the transcript.
1069
-
1070
- ## [15.8.2] - 2026-06-03
1071
-
1072
- ### Added
1073
-
1074
- - Added `PI_NO_SYNC_OUTPUT=1` to disable DEC 2026 synchronized-output wrappers for terminals whose implementation is buggy or visually worse, while keeping the renderer's autowrap guards active during paints ([#1765](https://github.com/can1357/oh-my-pi/issues/1765)).
1075
-
1076
- ### Fixed
1077
-
1078
- - Fixed terminal resizes that land in the same render frame as streamed output splicing a phantom blank row into native scrollback and offsetting every later row by one. A height shrink (or width change carrying an append) with content overflowing the viewport fell through to the differential emitter, whose scroll math is anchored to the pre-resize viewport top and hardware-cursor row — both invalidated by the terminal's own resize reflow. Geometry-changed frames now rebuild native history when the viewport is at (or possibly at) the bottom, and defer non-destructively for a reader confirmed scrolled into history.
1079
- - Fixed Ghostty/kitty/Alacritty-style ED3-risk terminals freezing the prompt after a deferred shrink; focused keyboard input now uses the same explicit user-input viewport opt-in as autocomplete and can repaint immediately instead of waiting for a resize.
1080
- - Deferred eager live scrollback rebuilds under WSL fronted by Windows Terminal (`WT_SESSION` present in a Linux environment) so foreground streaming no longer emits ED3 (`CSI 3 J`) and yanks a reader scrolled into Windows Terminal's host scrollback; deferred rewrites still reconcile at the next prompt-submit checkpoint ([#1610](https://github.com/can1357/oh-my-pi/issues/1610)).
1081
- - Fixed tmux (and screen/zellij) pane history gaining a complete duplicate copy of the transcript every time a deferred offscreen edit was followed by another render. Multiplexer panes never receive a destructive scrollback clear, so the dirty-scrollback rebuild path only appended the full transcript on top of preserved pane history — repeatedly. Live frames inside multiplexers now keep repainting the viewport and leave history reconciliation to explicit checkpoints, which also removes the O(transcript) write amplification per frame.
1082
- - Fixed tmux pane viewports corrupting and pane history duplicating when a resize coincides with rendering: a resize racing a streamed append reached the stale-anchor diff emitters (phantom rows in the pane), a forced render racing a resize replayed the whole transcript into preserved pane history, and the prompt-submit checkpoint did the same after any deferred offscreen edit. Geometry-changed frames inside multiplexers now repaint the viewport in place, and forced-render geometry replays plus checkpoint replays are disabled there — tmux reflows its own pane grid and its history cannot be cleared, only duplicated.
1083
- - Fixed terminal resize events whose dimensions net out unchanged by render time (rapid SIGWINCH round trips during a window drag, coalesced into one 16ms frame) being invisible to the renderer. The terminal reflows its buffer on every resize event — rows move between the viewport and scrollback and can be evicted at the scrollback cap — so diffing against the pre-resize screen splices blank phantom rows into the viewport. The renderer now tracks the resize event itself, not just the dimension delta, and routes such frames through the geometry-change repaint/rebuild paths.
1084
- - Fixed Termux terminal resizes (screen rotation or software-keyboard toggles) displacing or hiding output after the viewport height changed. Content-bearing resizes were routed to the differential emitter, whose scroll math is anchored to the pre-resize viewport, so appended rows landed too low; pure height changes were treated as no-ops, exposing blank rows that later appends could fill without growing native scrollback. Termux resizes now repaint or rebuild at the new geometry like every other non-multiplexer terminal.
1085
- - Fixed the turn-end teardown frame freezing on ED3-risk terminals (Ghostty/kitty/Alacritty/iTerm2): disabling eager scrollback rebuild now takes effect only after the in-flight frame is classified, so the loader/status removal still paints instead of deferring and leaving a stale spinner until the next keystroke.
1086
- - Fixed non-WT ConPTY terminals on Windows (Tabby, Hyper, VS Code, conhost) clearing scrollback and yanking the viewport to the top whenever streaming output or a prompt-submit rebuild arrived while the user was scrolled up. The kernel32 viewport probe describes the ConPTY pseudo-console buffer — which is pinned to the visible grid, invisible to host-UI scrollback — so it reported "at bottom" no matter where the user had scrolled, and the [#1635](https://github.com/can1357/oh-my-pi/issues/1635) fix only distrusted it under `WT_SESSION`, which Tabby and other ConPTY hosts never set. The probe is now removed entirely: every Windows host is treated as viewport-unobservable, live mutations defer destructive rebuilds (no `\x1b[3J`, no viewport movement), and native scrollback reconciles at the prompt-submit checkpoint where the Enter keystroke has already pinned the host viewport to the bottom ([#1746](https://github.com/can1357/oh-my-pi/issues/1746)).
1087
- - Fixed emoji-presentation symbols (a default-text symbol followed by variation-selector-16 `U+FE0F`, e.g. `⚠️`, `ℹ️`, `❤️`, keycaps) measuring as 1 cell instead of 2 in the native width engine on macOS. The native scanner now keeps `UnicodeWidthStr` as the source of truth for multi-codepoint graphemes and applies only the local macOS Hangul Compatibility Jamo character-width delta, preserving VS16/keycap sequence widths without reintroducing jamo cursor drift.
1088
- - Deferred eager live scrollback rebuilds on macOS Terminal.app and iTerm2 so assistant/tool streaming no longer emits ED3 (`CSI 3 J`) while their native viewport position is unobservable, preserving readers scrolled into terminal history ([#1300](https://github.com/can1357/oh-my-pi/issues/1300)).
1089
- - Fixed width-shrink reflow leaving old-width rows in native history so later appends no longer undercount scrollback growth or duplicate wrapped content.
1090
- - Fixed hiding overlays after terminal reflow so stale dialog rows are scrubbed from native scrollback on non-multiplexer terminals.
1091
-
1092
- ### Removed
1093
-
1094
- - Removed `shouldTrustNativeViewportProbe` and `ProcessTerminal`'s kernel32 `GetConsoleScreenBufferInfo` viewport probe. No Windows environment can answer "is the user's viewport at the bottom" truthfully — under ConPTY (every modern host) the pseudo-console buffer is pinned to the visible grid so the probe always read "at bottom", and under legacy conhost the window tracks the output cursor rather than the buffer tail so it always read "scrolled up" — so the probe and its trust gate are gone; `ProcessTerminal` no longer implements the optional `Terminal.isNativeViewportAtBottom`.
1095
-
1096
- ## [15.8.1] - 2026-06-02
1097
-
1098
- ### Fixed
1099
-
1100
- - Deferred eager live scrollback rebuilds on VTE terminals so GNOME-style Linux terminals do not flash or erase readable scrollback during streaming ([#1719](https://github.com/can1357/oh-my-pi/issues/1719)).
1101
-
1102
- ## [15.8.0] - 2026-06-02
1103
-
1104
- ### Fixed
1105
-
1106
- - Deferred eager live scrollback rebuilds on POSIX terminals where xterm ED3 (`CSI 3 J`, erase saved lines) can disturb scrolled-up readers during streaming, while keeping direct user-input and checkpoint rebuilds explicit ([#1682](https://github.com/can1357/oh-my-pi/issues/1682)).
1107
- - Fixed TUI shutdown placing the parent shell prompt one row below short rendered content instead of directly on the next line ([#1620](https://github.com/can1357/oh-my-pi/issues/1620)).
1108
- - Stopped painting inline color swatches for 4-digit hex runs in Markdown rendering. The `#RGBA` CSS form collides with hashline `#TAG` snapshot tags (4 hex digits, e.g. `#6C5E`), which were sprouting spurious RGB swatches in prose and codespans. Only `#RGB`, `#RRGGBB`, and `#RRGGBBAA` qualify now.
1109
-
1110
- ## [15.7.6] - 2026-06-01
1111
-
1112
- ### Fixed
1113
-
1114
- - Fixed native Windows + Windows Terminal freezing the editor on the wrap keystroke, on `/plan`/`/resume`/model-switch/status-line toggles, and on any other offscreen structural mutation until the next prompt submit. The `15.7.5` `#1635` fix routed every viewport-saturating pure-append and structural mutation through `deferredMutation` (a literal no-op) whenever `isNativeViewportAtBottom()` returned `undefined` — which it always does under `WT_SESSION` because the kernel32 probe can't see WT host scrollback. The deferral was only ever meant for the *confirmed-scrolled* case; an unknown viewport now falls back to a non-destructive `viewportRepaint` instead, so the live UI keeps updating without emitting `\x1b[3J` and without yanking a possibly-scrolled reader. Confirmed-scrolled frames (probe returns `false`) still defer.
1115
- - Removed the hard-coded 20-result cap on `@`-prefixed fuzzy file completion in `CombinedAutocompleteProvider.#getFuzzyFileSuggestions`. The dropdown now honors the existing `maxResults: 100` ceiling already configured for `fuzzyFind`, so projects with many files sharing a common stem (e.g. `@controller`, `@test`) surface all relevant matches instead of being silently truncated. ([#1652](https://github.com/can1357/oh-my-pi/issues/1652))
1116
-
1117
- ## [15.7.5] - 2026-06-01
1118
-
1119
- ### Fixed
1120
-
1121
- - Fixed native Windows + Windows Terminal scrollback being yanked to the top when a streaming response triggered a TUI full redraw. Under ConPTY the `kernel32` `GetConsoleScreenBufferInfo` probe answers about the pseudo-console (always at the buffer tail) and not about WT's host scrollback, so `isNativeViewportAtBottom()` falsely returned `true` while the user was scrolled up and the shrink-across-viewport branch issued a destructive `historyRebuild` (`\x1b[2J\x1b[H\x1b[3J`). The probe now short-circuits to `undefined` whenever `WT_SESSION` is set, letting the existing deferred-rebuild path keep streaming-time mutations non-destructive and reconcile native history at the next prompt-submit checkpoint. ([#1635](https://github.com/can1357/oh-my-pi/issues/1635))
1122
-
1123
- ## [15.7.3] - 2026-05-31
1124
-
1125
- ### Added
1126
-
1127
- - Added `overflowSearch` to `SelectListLayoutOptions` to let consumers enable or disable type-to-filter search and search-status rendering per SelectList instance
1128
- - Added fuzzy type-to-filter search to overflowing `SelectList` pickers, with search status and result counts.
1129
- - Added `TUI.setEagerNativeScrollbackRebuild(enabled)` — while enabled, live render frames rebuild native scrollback on offscreen/structural changes even when the viewport position is unobservable (POSIX), instead of deferring to a non-destructive repaint. Trades the anti-yank guarantee for clean, duplicate-free history; intended for windows where output above the fold is actively re-laying out (e.g. a tool whose result is still streaming). A terminal that reports a known-scrolled viewport still defers.
1130
-
1131
- ### Changed
1132
-
1133
- - Disabled interactive search filtering for editor autocomplete and slash-command `SelectList`s by passing `overflowSearch: false` in their layout options
1134
-
1135
- ### Fixed
1136
-
1137
- - Preserved hidden tmux overlays in the live viewport by removing overlay content from view when an overlay was hidden while keeping pane history intact
1138
- - Preserved native scrollback when forced TUI renders coalesce with content growth, and deferred pure tail appends while readers are scrolled into history.
1139
- - Preserved existing terminal scrollback during forced and structural TUI renders so preexisting shell lines remained visible after component mutations
1140
- - Rebuilt native scrollback for safe bottom-anchored offscreen edits and high-water preview collapses instead of repainting only the viewport, preventing stale or duplicated rows above the live viewport.
1141
- - Stripped internal cursor marker sentinels from all rendered lines so offscreen focus markers no longer leak into terminal output
1142
- - Truncated all painted lines to terminal width during viewport repaints and append-tail updates so long content no longer overflows or wraps unexpectedly
1143
- - Fixed `tui.select.cancel` handling in `SelectList` so pressing Escape or Ctrl+C closes the list even when no matches are currently shown
1144
- - Fixed native scrollback corruption when an offscreen row edit and repeated-tail append land in one render frame; ambiguous appended tails now rebuild history instead of splicing stale rows into the buffer.
1145
- - Fixed scrolled-up readers being yanked back to the tail whenever streaming content arrived on POSIX terminals (macOS/Linux). Native viewport position is unobservable there (`isNativeViewportAtBottom()` returns `undefined`), and the planner optimistically treated "unknown" as "at bottom", so every offscreen streaming edit ran a destructive `historyRebuild` that cleared scrollback and snapped the view to the bottom. Live render frames now treat an unknown viewport as unsafe for a destructive rebuild — they defer to a non-destructive viewport repaint and reconcile native scrollback at the next explicit checkpoint (prompt submit). Resize and checkpoint replays keep the prior behavior.
1146
- - Fixed native scrollback not rewrapping when the terminal widens on POSIX. A width increase reflows the transcript to fewer lines, which the shrink-across-boundary branch intercepted and (after the unknown-viewport deferral) repainted only the viewport — leaving committed history wrapped at the old width and duplicated above the live viewport. Width changes now rebuild native scrollback at the new geometry even when the viewport position is unknown (a yank is acceptable on an explicit resize); a terminal that can report a scrolled viewport still defers.
1147
-
1148
- ## [15.7.0] - 2026-05-31
1149
-
1150
- ### Fixed
1151
-
1152
- - Fixed slash-command autocomplete repainting when a Windows Terminal session cannot report native scrollback position; live input renders can now bypass the unknown-viewport deferral without weakening background scrollback protection. ([#1550](https://github.com/can1357/oh-my-pi/issues/1550))
1153
-
1154
- ## [15.6.0] - 2026-05-30
1155
-
1156
- ### Added
1157
-
1158
- - Added autocomplete triggering for internal URL scheme tokens such as `local://` and `skill://` while typing in the editor
1159
-
1160
- ### Fixed
1161
-
1162
- - Fixed streaming output staying invisible in Windows Terminal + WSL2 until the window was minimized + restored. The 15.5.14 WSL branch of `requiresNativeViewportProofForReplay` treated an unknown native viewport state as "scrolled into history" — but `ProcessTerminal.isNativeViewportAtBottom` can only return a real answer through `kernel32.dll` FFI, which a Linux user-space process inside WSL cannot load, so the probe was permanently `undefined`. Every row-inserting structural mutation (each new streaming token row above the bottom-anchored prompt) was therefore classified as `deferredMutation` and emitted zero bytes. Any geometry change (resize/minimize/restore) bypassed the gate via a different render intent, which is why the output became visible only on window resize. The WSL clause is removed; on platforms where the probe cannot answer, unknown is treated as at-bottom (the pre-15.5.14 behaviour) so the live render path runs again. Native Win32 keeps the conservative "assume scrolled when unknown" heuristic since `kernel32` FFI does succeed there and unknown means the probe transiently failed. ([#1534](https://github.com/can1357/oh-my-pi/issues/1534))
1163
-
1164
- ## [15.5.14] - 2026-05-29
1165
-
1166
- ### Added
1167
-
1168
- - `Markdown` now renders a small color-chip swatch, painted with the referenced color, in front of CSS hex colors mentioned in prose, thinking traces, lists, tables, and blockquotes (e.g. `#C5FFD6` or `` `#C5FFD6` ``). The chip glyph comes from the theme's symbol set so it degrades across tiers (Nerd Font / Unicode `■` → ASCII `[]`) and is overridable via the `md.colorSwatch` symbol. Truecolor terminals get an exact 24-bit chip; others fall back to the nearest 256-color cell. Bare prose requires a hex letter for 3/4-digit forms so short issue/PR references (`#123`, `#1011`) don't sprout swatches; backticked codes are always treated as colors.
1169
-
1170
- ### Fixed
1171
-
1172
- - Fixed the terminal hardware cursor disappearing in Ghostty. `resolveHardwareCursorPreference` force-hid the hardware cursor whenever it detected a Ghostty session (to fight bar-cursor afterimage "trails"), but the editor was simultaneously kept in terminal-cursor (marker-only) mode via `getUseTerminalCursorMarker()`, which renders no glyph and relies on the now-hidden hardware cursor — so Ghostty users had no visible caret at all, regardless of `PI_HARDWARE_CURSOR`. The Ghostty/`PI_FORCE_HARDWARE_CURSOR` override and the redundant `useTerminalCursorMarker` state are removed: `showHardwareCursor` is honored as-requested again (hardware cursor on by default), and disabling it cleanly falls back to the steady software-cursor glyph. The per-paint anti-trail mitigations (hide-cursor + autowrap-off inside the synchronized-output block) are retained, which is the actual trail fix.
1173
-
1174
- ## [15.5.12] - 2026-05-29
1175
-
1176
- ### Fixed
1177
-
1178
- - Fixed terminal resizes corrupting native scrollback with duplicated rows. The 15.4.0 change that defers a destructive scrollback clear+replay (so a user scrolled into history is not yanked while a streaming tail cell mutates) also caught genuine width/height resizes: a resize reflows the terminal's own committed scrollback at the new geometry, but repainting only the viewport left the stale old-size rows in history, so every overflowed row showed up twice (old-size wrap + new-size copy) when scrolling back, until the next prompt submit cleaned it up. `#planRender` now rebuilds history synchronously when the frame's geometry actually changed (`widthChanged || heightChanged`) via the restored `historyRebuild` intent, and defers the rebuild only for pure content mutations where the user may be reading scrollback mid-stream.
1179
-
1180
- ## [15.5.0] - 2026-05-26
1181
-
1182
- ### Fixed
1183
-
1184
- - Fixed `@` file mention autocomplete stalling for seconds when the query references something outside the project root (e.g. `@../`, `@~/`, `@/abs/`). `CombinedAutocompleteProvider` now short-circuits to plain immediate-directory prefix listing in those cases instead of dispatching a recursive `fuzzyFind` walk over a sibling directory full of unrelated projects. Inside-cwd queries keep the existing fuzzy-then-prefix behavior. ([#1395](https://github.com/can1357/oh-my-pi/issues/1395))
1185
- - Gated the Hangul Compatibility Jamo width correction (U+3131..U+318E → 1 cell, originally landed in 15.0.1 for the IME / hardware-cursor displacement bug) behind `process.platform === "darwin"` in the TS path and `cfg!(target_os = "macos")` in the `pi-natives` Rust path. macOS terminals (Ghostty / Terminal.app / iTerm2) render jamo as 1 cell despite UAX#11 classifying them as Wide, but WezTerm and most Linux terminals honor UAX#11 and render them as 2 cells. The unconditional correction therefore desynced the TUI's column bookkeeping from the terminal's actual rendering off-darwin, producing corrupted layout and broken Korean input on Linux. On non-darwin the helpers now defer entirely to `Bun.stringWidth` / `UnicodeWidthStr` (also a small perf win on the multi-char-grapheme path). ([#1410](https://github.com/can1357/oh-my-pi/issues/1410))
1186
-
1187
- ## [15.4.0] - 2026-05-26
1188
-
1189
- ### Fixed
1190
-
1191
- - Fixed terminal scrollback gaining duplicate copies of the welcome screen (and any other header content) when the bottom tool cell mutated across the previous viewport boundary. Once a row scrolls into terminal history it cannot be retracted, so a subsequent shrink that would re-expose that row in the repainted viewport now clears stale scrollback and replays the transcript, then suppresses one immediate suffix-scroll frame so live status/editor chrome is not deposited twice. Multiplexer panes ignore `\x1b[3J`, so the recovery is gated on `!isMultiplexerSession()`.
1192
- - Fixed the IME / hardware cursor sticking to the bottom of the terminal after a resize that grew the viewport taller than the rendered transcript. `#emitViewportRepaint` always writes one row per screen line (padding empty rows past the content), so the post-write hardware cursor sits at screen row `height - 1`. The bookkeeping previously clamped the tracked cursor row to `lines.length - 1`, making `#cursorControlSequence`'s relative `rowDelta` underestimate the upward move by `(height - lines.length)` rows and pinning the cursor at the viewport bottom even though the focused component's `CURSOR_MARKER` was on a content row.
1193
-
1194
- ## [15.3.2] - 2026-05-25
1195
-
1196
- ### Fixed
1197
-
1198
- - Fixed `matchesKey(data, "ctrl+m")` (and the other named-key collisions: `ctrl+h`/`ctrl+i`/`ctrl+j`/`ctrl+[`) returning true for the bare `\r`/`\x08`/`\t`/`\n`/`\x1b` byte terminals send for Enter/Backspace/Tab/Escape in legacy mode. Binding a command to `Ctrl+M` no longer fires when the user presses Enter — the named key wins, and `ctrl+<colliding-letter>` matches only when the terminal disambiguates via the Kitty keyboard protocol or `modifyOtherKeys`. ([#1354](https://github.com/can1357/oh-my-pi/issues/1354))
1199
-
1200
- ## [15.2.3] - 2026-05-22
1201
-
1202
- ### Added
1203
-
1204
- - Added `SettingsList#setItems` to replace the entire settings list with a new items array while automatically clamping selection to a valid index
1205
-
1206
- ### Changed
1207
-
1208
- - Updated `Loader` to drive renders at ~60fps (16ms tick) while keeping spinner-frame advancement at 80ms so shimmer/animated message colorizers update smoothly without altering spinner cadence
1209
-
1210
- ## [15.1.9] - 2026-05-21
1211
-
1212
- ### Fixed
1213
-
1214
- - Fixed terminal probe responses (DA1, kitty keyboard, Mode 2031) leaking into the prompt as keystrokes when the response is split across stdin reads. `ProcessTerminal` now reassembles `\x1b[?<digits>...` private CSI fragments and dispatches the complete response through the existing pattern handlers. ([#1238](https://github.com/can1357/oh-my-pi/issues/1238))
1215
-
1216
- ## [15.1.4] - 2026-05-19
1217
-
1218
- ### Fixed
1219
-
1220
- - Fixed `renderInlineMarkdown` crashing with `TypeError: undefined is not an object (evaluating 'e.replace')` when called with a non-string value during streaming — partial JSON parsing leaves option label fields temporarily unpopulated, causing the ask tool renderer to fail. ([#1176](https://github.com/can1357/oh-my-pi/issues/1176))
1221
-
1222
- ## [15.0.2] - 2026-05-15
1223
-
1224
- ### Added
1225
-
1226
- - Restored the `Key` runtime helper on `@linxiraos/pi-tui` to mirror upstream `@mariozechner/pi-tui`'s surface. `Key.enter`, `Key.escape`, `Key.tab`, … return the canonical key-name strings; modifier methods (`Key.ctrl(k)`, `Key.shift(k)`, `Key.ctrlShift(k)`, etc.) build precisely-typed `KeyId` literals like `"ctrl+c"`. Pure runtime convenience for typed key-id construction — plugins built against the upstream package surface that import `Key` (e.g. `@plannotator/pi-extension`, `@juicesharp/rpiv-ask-user-question`) load again now that the specifier shim remaps them onto this package.
1227
-
1228
- ## [15.0.1] - 2026-05-14
1229
-
1230
- ### Breaking Changes
1231
-
1232
- - Increased the minimum required Bun version for the TUI package from >=1.3.7 to >=1.3.14
1233
-
1234
- ## [14.9.8] - 2026-05-12
1235
-
1236
- ### Added
1237
-
1238
- - Added `Terminal.setProgress(active)` to emit OSC 9;4 progress sequences with a ~1s keepalive interval so Ghostty does not clear the indicator during long-running work (ports pi-mono `a900d251` + `76bc605a`)
1239
- - Added optional `argumentHint?: string` to `SlashCommand`; rendered before the description in the autocomplete dropdown (ports pi-mono `aa25726e`)
1240
- - Added `VirtualTerminal.waitForRender()` test helper for the throttled render pipeline (ports pi-mono `41377ee8`)
1241
-
1242
- ### Changed
1243
-
1244
- - `ProcessTerminal` `columns`/`rows` getters consult `Bun.env.COLUMNS` / `Bun.env.LINES` before falling back to 80×24, so piped/non-TTY runs honour environment-provided dimensions (ports pi-mono `32f7fc6a`)
1245
- - `requestRender()` non-force calls are coalesced to a ~16ms frame budget; `requestRender(true)` still flushes immediately via `process.nextTick` (ports pi-mono `6f5f37f8`)
1246
- - `KNOWN_TERMINALS.base` / `KNOWN_TERMINALS.trueColor` default `hyperlinks: false`; tmux and screen (`TMUX` env or `TERM` starts with `tmux`/`screen`) force `hyperlinks: false` even when the outer terminal would advertise OSC 8 (adapts pi-mono `30a8a41f`)
1247
- - `SlashCommand.getArgumentCompletions()` may return a `Promise`; results are now awaited and non-array returns are ignored (ports pi-mono `a1e10789`)
1248
- - Fuzzy `@` autocomplete now follows symlinked directories via `ScanOptions.follow_links` plumbed through the native walker (ports pi-mono `780d5367`)
1249
- - Plain `@<query>` (no slash) fuzzy matches by basename only, so `@plan` no longer surfaces every file whose ancestor directories contain `plan` (ports pi-mono `968430f6`)
1250
- - Changed slash-command autocomplete list rendering to combine command hint and description in a single displayed suggestion text
1251
- - Changed render scheduling to throttle `requestRender` calls to roughly 60fps by batching updates
1252
- - Changed terminal input handling to process complete cell-size responses without buffering partial input
1253
- - Changed `KeyId` to accept super-modifier combinations and improve typed key-id validation
1254
-
1255
- ### Fixed
1256
-
1257
- - Fixed editor corruption on Thai Sara Am (U+0E33) and Lao AM (U+0EB3) vowels by normalizing to their compatibility decompositions on the terminal-write path while keeping editor content logically unchanged (ports pi-mono `bc668826` + `338ce3a3` + `20ca45d5`)
1258
- - Fixed cell-size detection (`CSI 6;h;w t` response) to consume only exact replies, so a bare `Escape` keystroke is no longer swallowed while waiting for terminal image metadata (ports pi-mono `49c0d860`)
1259
- - Fixed Kitty CSI-u printable input duplicating on layouts (e.g. Italian) where the terminal also emits the raw character: the immediately-following matching codepoint is now suppressed (ports pi-mono `bdb416cb`)
1260
- - Fixed bracketed-paste CSI-u `Ctrl+<letter>` re-encoding (tmux popup with `extended-keys-format=csi-u`) leaking literal `[<code>;5u` into the editor; control bytes are decoded back to their literal byte before per-char filtering (ports pi-mono `d06db09a`)
1261
- - Fixed xterm `modifyOtherKeys` shifted printable input so uppercase letters inserted via `CSI 27;mod;codepoint~` reach the editor correctly (ports pi-mono `6b55d685`)
1262
- - Fixed `super`-modified Kitty shortcuts (`super+k`, `ctrl+super+enter`, …) to parse and match via the new `KITTY_MOD_SUPER` mask (ports pi-mono `ddb8454c` + `5ed46003`)
1263
- - Fixed `ctrl+alt+<letter>` in tmux falling through to CSI-u / `modifyOtherKeys` when the legacy `ESC<ctrl-char>` form does not match (ports pi-mono `6cf5098f`)
1264
- - Fixed Markdown strikethrough requiring strict `~~text~~` delimiters with non-whitespace boundaries; single tildes no longer render strikethrough (ports pi-mono `db5274b4`)
1265
- - Allowed `SlashCommand.getArgumentCompletions` to return asynchronous results by accepting Promise-based completions
1266
- - Added `argumentHint` support to slash command definitions and displayed it in command suggestion descriptions
1267
- - Added support for xterm `modifyOtherKeys` printable key sequences by decoding `CSI 27;mod;key~` into text input
1268
- - Normalized line output during rendering to correct Thai/Lao AM glyph composition for displayed text
1269
- - Fixed duplicated Kitty key input emissions by dropping the matching unmodified follow-up sequence after a Kitty CSI-u printable-key event
1270
-
1271
- ## [14.9.5] - 2026-05-12
1272
-
1273
- ### Fixed
1274
-
1275
- - Fixed rapidly blinking cursor artifact during task execution by consolidating cursor control sequences into the synchronized output buffer ([#992](https://github.com/can1357/oh-my-pi/issues/992))
1276
-
1277
- ## [14.5.7] - 2026-04-29
1278
-
1279
- ### Fixed
1280
-
1281
- - Fixed editor Ctrl+Enter handling to recognize NumLock and keypad Enter variants.
1282
-
1283
- ## [14.3.0] - 2026-04-25
1284
-
1285
- ### Fixed
1286
-
1287
- - Fixed shared Markdown Mermaid fenced-block rendering to resolve diagrams from fenced source text instead of external prerender state
1288
-
1289
- ## [14.1.1] - 2026-04-14
1290
-
1291
- ### Breaking Changes
1292
-
1293
- - Removed the `searchDb` constructor argument from `CombinedAutocompleteProvider`, requiring callers to use the built-in search behavior
1294
-
1295
- ### Changed
1296
-
1297
- - Changed truncation debug logging to run only when `debugRedraw` is enabled
1298
-
1299
- ## [14.0.5] - 2026-04-11
1300
-
1301
- ### Changed
1302
-
1303
- - Updated hash computation to use `Bun.hash()` instead of `Bun.hash.xxHash64()`, which may return `number` in addition to `bigint`
1304
- - Simplified cache key computation in Box component by removing intermediate hash updates and consolidating hash operations
1305
- - Wrapped native text utility functions (`sliceWithWidth`, `truncateToWidth`, `wrapTextWithAnsi`, `extractSegments`) to automatically pass the current default tab width, simplifying the API for consumers
1306
- - Added `getIndentationNoescape` wrapper that uses `process.cwd()` as the project root for relative file paths
1307
- - Re-export `getDefaultTabWidth`, `getIndentation`, and `setDefaultTabWidth` from `@linxiraos/pi-utils`; native text helpers still receive tab width via wrappers that read the JS default
1308
-
1309
- ## [13.16.1] - 2026-03-27
1310
-
1311
- ### Added
1312
-
1313
- - Support for optional SearchDb parameter in CombinedAutocompleteProvider constructor for improved fuzzy search performance
1314
- - Fuzzy matching filter for autocomplete suggestions to improve relevance of results
1315
-
1316
- ### Changed
1317
-
1318
- - Fuzzy discovery now applies fuzzy matching filter to results for improved relevance of autocomplete suggestions
1319
- - Autocomplete fuzzy discovery now accepts optional SearchDb instance for faster searches
1320
-
1321
- ## [13.16.0] - 2026-03-27
1322
-
1323
- ### Changed
1324
-
1325
- - Updated tab replacement in editor text sanitization to respect configured tab width setting
1326
-
1327
- ## [13.15.0] - 2026-03-23
1328
-
1329
- ### Added
1330
-
1331
- - Added `renderInlineMarkdown()` function to render inline markdown (bold, italic, code, links, strikethrough) to styled strings
1332
-
1333
- ### Fixed
1334
-
1335
- - Fixed editor consuming user-rebound copy keys, preventing custom keybindings from working in the editor
1336
-
1337
- ## [13.14.1] - 2026-03-21
1338
-
1339
- ### Added
1340
-
1341
- - Added Ctrl+_ as an additional default shortcut for undo
1342
-
1343
- ### Fixed
1344
-
1345
- - Ensured undo functionality respects user-configured keybindings
1346
-
1347
- ## [13.12.0] - 2026-03-14
1348
-
1349
- ### Added
1350
-
1351
- - Added `moveToMessageStart()` and `moveToMessageEnd()` methods to move cursor to the beginning and end of the entire message
1352
-
1353
- ### Fixed
1354
-
1355
- - Fixed autocomplete to preserve `./` prefix when completing relative file and directory paths
1356
- - Fixed paste marker expansion to handle special regex replacement tokens ($1, $2, $&, $$, $`, $') literally in pasted content
1357
-
1358
- ## [13.11.0] - 2026-03-12
1359
-
1360
- ### Fixed
1361
-
1362
- - Fixed OSC 11 background color detection to correctly handle partial escape sequences that arrive mid-buffer, preventing user input from being swallowed
1363
- - Fixed race condition where overlapping OSC 11 queries would be incorrectly cancelled by DA1 sentinels from previous queries
1364
-
1365
- ## [13.7.5] - 2026-03-04
1366
-
1367
- ### Changed
1368
-
1369
- - Extracted word navigation logic into reusable `moveWordLeft` and `moveWordRight` utility functions for consistent cursor movement across components
1370
-
1371
- ## [13.6.2] - 2026-03-03
1372
-
1373
- ### Fixed
1374
-
1375
- - Fixed cursor positioning when content shrinks to empty without clearOnShrink enabled
1376
-
1377
- ## [13.5.4] - 2026-03-01
1378
-
1379
- ### Fixed
1380
-
1381
- - Fixed viewport repaint scrollback accounting during resize oscillation to avoid double-scrolling on height shrink and added exact-row scrollback assertions in overlay regression coverage ([#228](https://github.com/can1357/oh-my-pi/issues/228), [#234](https://github.com/can1357/oh-my-pi/issues/234))
1382
-
1383
- ## [13.5.3] - 2026-03-01
1384
-
1385
- ### Fixed
1386
-
1387
- - Fixed append rendering logic to correctly handle offscreen header changes during content overflow growth, preserving scroll history integrity
1388
- - Fixed visible tail line updates when appending new content during viewport overflow conditions
1389
- - Fixed cursor positioning instability when appending content under external cursor relocation by using absolute screen addressing instead of relative cursor movement
1390
-
1391
- ## [13.5.2] - 2026-03-01
1392
-
1393
- ### Breaking Changes
1394
-
1395
- - Removed `getMermaidImage` callback from MarkdownTheme; replaced with `getMermaidAscii` that accepts ASCII string instead of image data
1396
- - Removed mermaid module exports (`renderMermaidToPng`, `extractMermaidBlocks`, `prerenderMermaidBlocks`, `MermaidImage` interface)
1397
-
1398
- ### Changed
1399
-
1400
- - Mermaid diagrams now render as ASCII text instead of terminal graphics protocol images
1401
-
1402
- ## [13.5.1] - 2026-03-01
1403
-
1404
- ### Fixed
1405
-
1406
- - Fixed viewport shift handling to prevent stale content when mixed updates remap screen rows
1407
-
1408
- ## [13.5.0] - 2026-03-01
1409
-
1410
- ### Breaking Changes
1411
-
1412
- - Removed `PI_TUI_RESIZE_CLEAR_STRATEGY`; resize behavior is no longer configurable between viewport/scrollback modes. The renderer now uses fixed semantics: width changes perform a hard reset (`3J` + full content rewrite), while height changes and diff fallbacks use viewport-scoped repainting.
1413
-
1414
- ### Added
1415
-
1416
- - Added a new terminal regression suite in `packages/tui/test/render-regressions.test.ts` covering no-op render stability, targeted middle-line diffs, shrink cleanup, width-resize truncation without ghost rows, shrink/grow viewport tail anchoring, scrollback deduplication across forced redraws, overlay restore behavior, and rapid mutation convergence.
1417
- - Expanded `packages/tui/test/overlay-scroll.test.ts` with stress coverage for overflow shrink/regrow cycles, resize oscillation, overlay toggle churn, no-op render loops, and hardware-cursor-only updates while bounding scrollback growth and blank-run artifacts.
1418
-
1419
- ### Changed
1420
-
1421
- - Refactored render orchestration to explicit `hardReset` and `viewportRepaint` paths, with targeted fallbacks for offscreen diff ranges and unsafe row deltas.
1422
- - Switched startup to `requestRender(true)` so the first frame always initializes renderer state with a forced full path.
1423
- - Replaced legacy viewport bookkeeping (`previousViewportTop`) with `viewportTopRow` tracking and consistent screen-relative cursor calculations.
1424
- - Updated stop-sequence cursor placement to target the visible working area and clamp to terminal bounds before final newline emission.
1425
- - Documented the intentional performance policy of not forcing full repaint on every viewport-top shift, relying on narrower safety guards instead.
1426
-
1427
- ### Fixed
1428
-
1429
- - Fixed stale/duplicated terminal cursor dedup state by synchronizing `#lastCursorSequence` in all render write paths (hard reset, viewport repaint, deleted-lines clear path, append fast path, and differential path).
1430
- - Fixed scroll overshoot on `stop()` when content fills the viewport by clamping target row movement to valid screen rows.
1431
-
1432
- ## [13.4.0] - 2026-03-01
1433
-
1434
- ### Added
1435
-
1436
- - Added `PI_TUI_RESIZE_CLEAR_STRATEGY` environment variable to control terminal behavior on resize: `viewport` (default) clears/redraws the viewport while preserving scrollback, or `scrollback` clears all history
1437
-
1438
- ### Changed
1439
-
1440
- - Changed resize redraw behavior to use configurable clear semantics (`viewport` vs `scrollback`) while keeping full content rendering for scrollback navigation
1441
-
1442
- ### Fixed
1443
-
1444
- - Fixed loader component rendering lines wider than terminal width, preventing text overflow and display artifacts
1445
-
1446
- ## [13.3.11] - 2026-02-28
1447
-
1448
- ### Fixed
1449
-
1450
- - Restored terminal image protocol override and fallback detection for image rendering, including `PI_FORCE_IMAGE_PROTOCOL` support and Kitty fallback for screen/tmux/ghostty-style TERM environments.
1451
-
1452
- ## [13.3.8] - 2026-02-28
1453
-
1454
- ### Breaking Changes
1455
-
1456
- - Changed mermaid hash type from string to bigint in `getMermaidImage` callback and `extractMermaidBlocks` return type
1457
- - Removed `mime-types` and `@types/mime-types` from dependencies
1458
- - Removed `@xterm/xterm` from dependencies
1459
-
1460
- ### Changed
1461
-
1462
- - Updated mermaid hash computation to use `Bun.hash.xxHash64()` instead of `Bun.hash().toString(16)`
1463
-
1464
- ## [12.19.0] - 2026-02-22
1465
-
1466
- ### Added
1467
-
1468
- - Added `getTopBorderAvailableWidth()` method to calculate available width for top border content accounting for border characters and padding
1469
-
1470
- ### Fixed
1471
-
1472
- - Fixed stale viewport rows appearing when terminal height increases by triggering full re-render on height changes
1473
-
1474
- ## [12.18.0] - 2026-02-21
1475
-
1476
- ### Fixed
1477
-
1478
- - Fixed viewport synchronization issue by clearing scrollback when terminal state becomes desynced during full re-renders
1479
-
1480
- ## [12.12.2] - 2026-02-19
1481
-
1482
- ### Fixed
1483
-
1484
- - Fixed non-forced full re-renders clearing terminal scrollback history during streaming updates by limiting scrollback clears to explicit forced re-renders.
1485
-
1486
- ## [12.12.0] - 2026-02-19
1487
-
1488
- ### Added
1489
-
1490
- - Added PageUp/PageDown navigation for editor content and autocomplete selection to jump across long wrapped inputs faster.
1491
-
1492
- ### Fixed
1493
-
1494
- - Fixed history-entry navigation anchoring (Up opens at top, Down opens at bottom) and preserved editor scroll context when max-height changes to keep cursor movement visible in long prompts ([#99](https://github.com/can1357/oh-my-pi/issues/99)).
1495
-
1496
- ## [12.11.3] - 2026-02-19
1497
-
1498
- ### Fixed
1499
-
1500
- - Fixed differential deleted-line rendering when content shrinks to empty so stale first-row content is cleared reliably.
1501
- - Fixed incremental stale-row clearing to use erase-below semantics in synchronized output, reducing leftover-line artifacts after shrink operations.
1502
-
1503
- ## [12.9.0] - 2026-02-17
1504
-
1505
- ### Added
1506
-
1507
- - Exported `getTerminalId()` function to get a stable identifier for the current terminal, with support for TTY device paths and terminal multiplexers
1508
- - Exported `getTtyPath()` function to resolve the TTY device path for stdin via POSIX `ttyname(3)`
1509
-
1510
- ## [12.5.0] - 2026-02-15
1511
-
1512
- ### Added
1513
-
1514
- - Added `cursorOverride` and `cursorOverrideWidth` properties to customize the end-of-text cursor glyph with ANSI-styled strings
1515
- - Added `getUseTerminalCursor()` method to query the terminal cursor mode setting
1516
-
1517
- ## [11.10.0] - 2026-02-10
1518
-
1519
- ### Added
1520
-
1521
- - Added `hint` property to autocomplete items to display dim ghost text after cursor when item is selected
1522
- - Added `getInlineHint()` method to `SlashCommand` interface for providing inline hint text based on argument state
1523
- - Added `getInlineHint()` method to `AutocompleteProvider` interface for displaying dim ghost text after cursor
1524
- - Added `hintStyle` theme option to customize styling of inline hint/ghost text in editor
1525
-
1526
- ### Changed
1527
-
1528
- - Updated editor to render inline hint text as dim ghost text after cursor when autocomplete suggestions are active or provider supplies hints
1529
-
1530
- ## [11.8.0] - 2026-02-10
1531
-
1532
- ### Added
1533
-
1534
- - Added Alt+Y keybinding to cycle through kill ring entries (yank-pop)
1535
- - Added undo support to Input component with Ctrl+Z keybinding
1536
- - Added kill ring support to Input component for Emacs-style kill/yank operations
1537
- - Added yank (Ctrl+Y) and yank-pop (Alt+Y) support to Input component
1538
-
1539
- ### Changed
1540
-
1541
- - Changed Editor kill ring implementation to use dedicated KillRing class for better state management
1542
- - Changed Editor undo stack to use generic UndoStack class with automatic state cloning
1543
- - Changed kill/yank behavior to properly accumulate consecutive kill operations
1544
- - Changed Input component deletion methods to record killed text in kill ring
1545
- - Changed undo coalescing in Input component to group consecutive word typing into single undo units
1546
-
1547
- ## [11.4.1] - 2026-02-06
1548
-
1549
- ### Fixed
1550
-
1551
- - Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of blank lines from being output
1552
-
1553
- ## [11.3.0] - 2026-02-06
1554
-
1555
- ### Breaking Changes
1556
-
1557
- - Removed `getCursorPosition()` method from Component interface and implementations, eliminating hardware cursor positioning support
1558
-
1559
- ### Added
1560
-
1561
- - Added sticky column behavior for vertical cursor movement, preserving target column when navigating through lines of varying lengths
1562
- - Added `drainInput()` method to Terminal interface to prevent Kitty key release events from leaking to parent shell over slow SSH connections
1563
- - Added `setClearOnShrink()` method to control whether full re-render occurs when content shrinks below working area
1564
- - Added support for hidden paths (e.g., `.pi`, `.github`) in autocomplete while excluding `.git` directories
1565
-
1566
- ### Changed
1567
-
1568
- - Changed default value of `PI_HARDWARE_CURSOR` environment variable from implicit true to explicit `"1"` for clarity
1569
- - Changed default value of `PI_CLEAR_ON_SHRINK` environment variable from implicit false to explicit `"0"` for clarity
1570
- - Changed TUI to clear screen on startup to prevent shell prompts and status messages from bleeding into the first rendered frame
1571
- - Refactored full-render logic into reusable helper function to reduce code duplication across multiple render paths
1572
- - Changed autocomplete to include hidden paths but filter out `.git` and its contents
1573
- - Changed Input component to properly handle surrogate pairs in Unicode text, preventing cursor display corruption with emoji and multi-byte characters
1574
- - Changed Editor to use `setCursorCol()` for all cursor column updates, enabling sticky column tracking
1575
- - Changed Editor's vertical navigation to implement sticky column logic via `moveToVisualLine()` and `computeVerticalMoveColumn()`
1576
- - Changed Editor's Enter key handling to extract submit logic into `submitValue()` method for better code organization
1577
- - Changed SettingsList to truncate long lines to viewport width, preventing text overflow
1578
- - Changed Terminal's `stop()` method to drain stdin before restoring raw mode, fixing race condition where Ctrl+D could close parent shell over SSH
1579
- - Changed TUI rendering to add `clearOnShrink` option (controlled by `PI_CLEAR_ON_SHRINK` env var) for reducing redraws on slower terminals
1580
- - Changed TUI rendering to detect when extra lines exceed viewport height and trigger full re-render instead of incremental updates
1581
-
1582
- ### Fixed
1583
-
1584
- - Fixed rendering of extra blank lines when content shrinks by improving cursor positioning logic during line deletion
1585
- - Fixed cursor display position in Input component when scrolling horizontally through long text
1586
- - Fixed Kitty keyboard protocol disable sequence to use safe write method, preventing potential output buffering issues
1587
- - Fixed unnecessary full-screen redraws when changes occur in out-of-view components (e.g., spinners), reducing terminal scroll events and improving performance on slower connections
1588
- - Fixed scrollback clearing behavior to only clear screen instead of scrollback when resizing or shrinking content, preventing loss of terminal history
1589
- - Fixed `.git` directory appearing in autocomplete suggestions when filtering by prefix
1590
- - Fixed cursor position corruption in Input component when displaying text with emoji and combining characters
1591
- - Fixed `.git` directory appearing in autocomplete suggestions
1592
- - Fixed race condition where Kitty key release events could leak to parent shell after TUI exit over slow SSH connections
1593
- - Fixed Editor's word movement (Ctrl+Left/Right) to properly reset sticky column for subsequent vertical navigation
1594
- - Fixed Editor's undo operation to reset sticky column state when restoring cursor position
1595
- - Fixed Editor's right arrow key at end of last line to set sticky column for subsequent up/down navigation
1596
- - Fixed TUI rendering to correctly detect viewport changes and avoid false full-redraws after content shrinks
1597
- - Fixed Kitty protocol key parsing to prefer codepoint over base layout for Latin letters and symbols, fixing keyboard layout issues (e.g., Dvorak)
1598
-
1599
- ## [11.0.0] - 2026-02-05
1600
-
1601
- ### Added
1602
-
1603
- - Introduced `terminal-capabilities.ts` module consolidating terminal detection and image protocol support
1604
- - Added `TerminalInfo` class with methods for detecting image lines and formatting notifications
1605
- - Added `NotifyProtocol` enum supporting Bell, OSC 99, and OSC 9 notification protocols
1606
- - Added `isNotificationSuppressed()` function to check `OMP_NOTIFICATIONS` environment variable
1607
- - Added `TERMINAL` constant providing detected terminal capabilities at runtime
1608
-
1609
- ### Changed
1610
-
1611
- - Changed notification suppression environment variable from `OMP_NOTIFICATIONS` to `PI_NOTIFICATIONS`
1612
- - Changed TUI write log environment variable from `OMP_TUI_WRITE_LOG` to `PI_TUI_WRITE_LOG`
1613
- - Changed hardware cursor environment variable from `OMP_HARDWARE_CURSOR` to `PI_HARDWARE_CURSOR`
1614
- - Updated environment variable access to use `getEnv()` utility function from `@linxiraos/pi-utils` for consistent handling
1615
- - Renamed `TERMINAL_INFO` export to `TERMINAL` for clearer API semantics
1616
- - Reorganized terminal image exports from `terminal-image` to `terminal-capabilities` module
1617
- - Updated all internal references to use `TERMINAL` instead of `TERMINAL_INFO`
1618
-
1619
- ### Removed
1620
-
1621
- - Removed `terminal-image` module exports from public API (functionality migrated to `terminal-capabilities`)
1622
-
1623
- ## [10.5.0] - 2026-02-04
1624
-
1625
- ### Fixed
1626
-
1627
- - Treated inline image lines with cursor-move prefixes as image sequences to prevent width overflow crashes
1628
-
1629
- ## [9.8.0] - 2026-02-01
1630
-
1631
- ### Changed
1632
-
1633
- - Moved `wrapTextWithAnsi` export to `@linxiraos/pi-natives` package
1634
-
1635
- ### Fixed
1636
-
1637
- - Improved Kitty terminal key sequence parsing to correctly handle text field codepoints in CSI-u sequences
1638
- - Fixed handling of private use Unicode codepoints (U+E000 to U+F8FF) in Kitty key decoding to prevent invalid character interpretation
1639
-
1640
- ## [9.7.0] - 2026-02-01
1641
-
1642
- ### Breaking Changes
1643
-
1644
- - Removed `Key` helper object from public API; use string literals like `"ctrl+c"` instead of `Key.ctrl("c")`
1645
- - Removed `KeyEventType` export from public API
1646
-
1647
- ### Changed
1648
-
1649
- - Migrated key parsing and matching logic to native implementation for improved performance
1650
- - Simplified `isKeyRelease()` and `isKeyRepeat()` to use regex pattern matching instead of string inclusion checks
1651
-
1652
- ## [9.6.2] - 2026-02-01
1653
-
1654
- ### Changed
1655
-
1656
- - Renamed `EllipsisKind` enum to `Ellipsis` for clearer API naming
1657
- - Changed hardcoded ellipsis character from theme-configurable to literal "…" in editor truncation
1658
- - Refactored `visibleWidth` function to use caching wrapper around new `visibleWidthRaw` implementation for improved performance
1659
-
1660
- ### Removed
1661
-
1662
- - Removed `truncateToWidth`, `sliceWithWidth`, and `extractSegments` functions from public API (now re-exported directly from @linxiraos/pi-natives)
1663
- - Removed `ellipsis` property from `SymbolTheme` interface
1664
- - Removed `extractAnsiCode` function from public API
1665
-
1666
- ## [9.6.1] - 2026-02-01
1667
-
1668
- ### Changed
1669
-
1670
- - Improved performance of key ID parsing with optimized cache lookup strategy
1671
- - Simplified `visibleWidth` calculation to use consistent Bun.stringWidth approach for all string lengths
1672
-
1673
- ### Removed
1674
-
1675
- - Removed `visibleWidth` benchmark file in favor of Kitty sequence benchmarking
1676
-
1677
- ## [9.5.0] - 2026-02-01
1678
-
1679
- ### Changed
1680
-
1681
- - Improved fuzzy file search performance by using native implementation instead of spawning external process
1682
- - Replaced external `fd` binary with native fuzzy path search for `@`-prefixed autocomplete
1683
-
1684
- ## [9.4.0] - 2026-01-31
1685
-
1686
- ### Added
1687
-
1688
- - Exported `padding` utility function for creating space-padded strings efficiently
1689
-
1690
- ### Changed
1691
-
1692
- - Optimized padding operations across all components to use pre-allocated space buffer for better performance
1693
-
1694
- ## [9.2.2] - 2026-01-31
1695
-
1696
- ### Added
1697
-
1698
- - Added setAutocompleteMaxVisible() configuration (3-20 items)
1699
- - Added image detection to terminal capabilities (containsImage method)
1700
- - Added stdin monitoring to detect stalled input events and log warnings
1701
-
1702
- ### Changed
1703
-
1704
- - Improved blockquote rendering with text wrapping in Markdown component
1705
- - Restructured terminal capabilities from interface-based to class-based model
1706
- - Improved table column width calculation with word-aware wrapping
1707
- - Refactored text utilities to use native WASM implementations for strings >256 chars with JS fast path
1708
-
1709
- ### Fixed
1710
-
1711
- - Simplified terminal write error handling to mark terminal as dead on any write failure
1712
- - Fixed multi-line strings in renderOutputBlock causing width overflow
1713
- - Fixed slash command autocomplete applying stale completion when typing quickly
1714
-
1715
- ### Removed
1716
-
1717
- - Removed TUI layout engine exports from public API (BoxNode, ColumnNode, LayoutNode, etc.)
1718
-
1719
- ## [8.12.7] - 2026-01-29
1720
-
1721
- ### Fixed
1722
-
1723
- - Fixed slash command autocomplete applying stale completion when typing quickly
1724
-
1725
- ## [8.4.1] - 2026-01-25
1726
-
1727
- ### Added
1728
-
1729
- - Added fuzzy match function for autocomplete suggestions
1730
-
1731
- ## [8.4.0] - 2026-01-25
1732
-
1733
- ### Changed
1734
-
1735
- - Added Ctrl+Backspace as a delete-word-backward keybinding and improved modified backspace matching
1736
-
1737
- ### Fixed
1738
-
1739
- - Terminal gracefully handles write failures by marking dead instead of exiting the process
1740
- - Reserved cursor space for zero padding and corrected end-of-line cursor rendering to prevent wrap glitches
1741
- - Corrected editor end-of-line cursor rendering assertion to use includes() instead of endsWith()
1742
-
1743
- ## [8.2.0] - 2026-01-24
1744
-
1745
- ### Added
1746
-
1747
- - Added mermaid diagram rendering engine (renderMermaidToPng) with mmdc CLI integration
1748
- - Added terminal graphics encoding (iTerm2/Kitty) for mermaid diagrams with automatic width scaling
1749
- - Added mermaid block extraction and deduplication utilities (extractMermaidBlocks)
1750
-
1751
- ### Changed
1752
-
1753
- - Updated TypeScript configuration for better publish-time configuration handling with tsconfig.publish.json
1754
- - Migrated file system operations from synchronous to asynchronous APIs in autocomplete provider for non-blocking I/O
1755
- - Migrated node module imports from named to namespace imports across all packages for consistency with project guidelines
1756
-
1757
- ### Fixed
1758
-
1759
- - Fixed crash when terminal becomes unavailable (EIO errors) by exiting gracefully instead of throwing
1760
- - Fixed potential errors during emergency terminal restore when terminal is already dead
1761
- - Fixed autocomplete race condition by tracking request ID to prevent stale suggestion results
1762
-
1763
- ## [6.8.3] - 2026-01-21
1764
-
1765
- ### Added
1766
-
1767
- - Added undo support in the editor via `Ctrl+-`
1768
- - Added `Alt+Delete` as a delete-word-forward shortcut
1769
- - Added configurable code block indentation for Markdown rendering
1770
- - Added undo support in the editor via `Ctrl+-`.
1771
- - Added configurable code block indentation for Markdown rendering.
1772
- - Added `Alt+Delete` as a delete-word-forward shortcut.
1773
-
1774
- ### Changed
1775
-
1776
- - Improved fuzzy matching to handle alphanumeric swaps
1777
- - Normalized keybinding definitions to lowercase internally
1778
- - Improved fuzzy matching to handle alphanumeric swaps.
1779
- - Normalized keybinding definitions to lowercase internally.
1780
-
1781
- ### Fixed
1782
-
1783
- - Added legacy terminal support for `Ctrl+` symbol key combinations
1784
- - Added legacy terminal support for `Ctrl+` symbol key combinations.
1785
-
1786
- ## [6.8.1] - 2026-01-20
1787
-
1788
- ### Fixed
1789
-
1790
- - Fixed viewport tracking after partial renders to prevent autocomplete list artifacts
1791
-
1792
- ## [5.6.7] - 2026-01-18
1793
-
1794
- ### Added
1795
-
1796
- - Added configurable editor padding via `editorPaddingX` theme option
1797
- - Added `setMaxHeight()` method to limit editor height with scrolling
1798
- - Added Emacs-style kill ring for text deletion operations
1799
- - Added `Alt+D` keybinding to delete words forward
1800
- - Added `Ctrl+Y` keybinding to yank from kill ring
1801
- - Added `waitForRender()` method to await pending renders
1802
- - Added Focusable interface and hardware cursor marker support for IME positioning
1803
- - Added support for shifted symbol keys in keybindings
1804
-
1805
- ### Changed
1806
-
1807
- - Updated tab bar rendering to wrap text across multiple lines when content exceeds available width
1808
- - Expanded Kitty keyboard protocol coverage for non-Latin layouts and legacy Alt sequences
1809
- - Improved cursor positioning with safer bounds checking
1810
- - Updated editor layout to respect configurable padding
1811
- - Refactored scrolling logic for better viewport management
1812
-
1813
- ### Fixed
1814
-
1815
- - Fixed key detection for shifted symbol characters
1816
- - Fixed backspace handling with additional codepoint support
1817
- - Fixed Alt+letter key combinations for better recognition
1818
-
1819
- ## [5.3.1] - 2026-01-15
1820
-
1821
- ### Fixed
1822
-
1823
- - Fixed rendering issues on Windows by preventing re-entrant renders
1824
-
1825
- ## [5.1.0] - 2026-01-14
1826
-
1827
- ### Added
1828
-
1829
- - Added `pageUp` and `pageDown` key support with `selectPageUp`/`selectPageDown` editor actions
1830
- - Added `isPageUp()` and `isPageDown()` helper functions
1831
- - Added `SizeValue` type for CSS-like overlay sizing (absolute or percentage strings like `"50%"`)
1832
- - Added `OverlayHandle` interface with `hide()`, `setHidden()`, `isHidden()` methods for overlay visibility control
1833
- - Added `visible` callback to `OverlayOptions` for dynamic visibility based on terminal dimensions
1834
- - Added `pad` parameter to `truncateToWidth()` for padding result with spaces to exact width
1835
-
1836
- ### Changed
1837
-
1838
- - Changed `OverlayOptions` to use `SizeValue` type for `width`, `maxHeight`, `row`, and `col` properties
1839
- - Changed `showOverlay()` to return `OverlayHandle` for controlling overlay visibility
1840
- - Removed `widthPercent`, `maxHeightPercent`, `rowPercent`, `colPercent` from `OverlayOptions` (use percentage strings instead)
1841
-
1842
- ### Fixed
1843
-
1844
- - Fixed numbered list items showing "1." for all items when code blocks break list continuity
1845
- - Fixed width overflow protection in overlay compositing to prevent TUI crashes
1846
-
1847
- ## [4.7.0] - 2026-01-12
1848
-
1849
- ### Fixed
1850
-
1851
- - Remove trailing space padding from Text, Markdown, and TruncatedText components when no background color is set (fixes copied text including unwanted whitespace)
1852
-
1853
- ## [4.6.0] - 2026-01-12
1854
-
1855
- ### Added
1856
-
1857
- - Add fuzzy matching module (`fuzzyMatch`, `fuzzyFilter`) for command autocomplete
1858
- - Add `getExpandedText()` to editor for expanding paste markers
1859
- - Add backslash+enter newline fallback for terminals without Kitty protocol
1860
-
1861
- ### Fixed
1862
-
1863
- - Remove Kitty protocol query timeout that caused shift+enter delays
1864
- - Add bracketed paste check to prevent false key release/repeat detection
1865
- - Rendering optimizations: only re-render changed lines
1866
- - Refactor input component to use keybindings manager
1867
-
1868
- ## [4.4.4] - 2026-01-11
1869
-
1870
- ### Fixed
1871
-
1872
- - Fixed Ctrl+Enter sequences to insert new lines in the editor
1873
-
1874
- ## [4.2.1] - 2026-01-11
1875
-
1876
- ### Changed
1877
-
1878
- - Improved file autocomplete to show directory listing when typing `@` with no query, and fall back to prefix matching when fuzzy search returns no results
1879
-
1880
- ### Fixed
1881
-
1882
- - Fixed editor redraw glitch when canceling autocomplete suggestions
1883
- - Fixed `fd` tool detection to automatically find `fd` or `fdfind` in PATH when not explicitly configured
1884
-
1885
- ## [4.1.0] - 2026-01-10
1886
-
1887
- ### Added
1888
-
1889
- - Added persistent prompt history storage support via `setHistoryStorage()` method, allowing history to be saved and restored across sessions
1890
-
1891
- ## [4.0.0] - 2026-01-10
1892
-
1893
- ### Added
1894
-
1895
- - `EditorComponent` interface for custom editor implementations
1896
- - `StdinBuffer` class to split batched stdin into individual sequences
1897
- - Overlay compositing via `TUI.showOverlay()` and `TUI.hideOverlay()` for `ctx.ui.custom()` with `{ overlay: true }`
1898
- - Kitty keyboard protocol flag 2 support for key release events (`isKeyRelease()`, `isKeyRepeat()`, `KeyEventType`)
1899
- - `setKittyProtocolActive()`, `isKittyProtocolActive()` for Kitty protocol state management
1900
- - `kittyProtocolActive` property on Terminal interface to query Kitty protocol state
1901
- - `Component.wantsKeyRelease` property to opt-in to key release events (default false)
1902
- - Input component `onEscape` callback for handling escape key presses
1903
-
1904
- ### Changed
1905
-
1906
- - Terminal startup now queries Kitty protocol support before enabling event reporting
1907
- - Default editor `newLine` binding now uses `shift+enter` only
1908
-
1909
- ### Fixed
1910
-
1911
- - Key presses no longer dropped when batched with other events over SSH
1912
- - TUI now filters out key release events by default, preventing double-processing of keys
1913
- - `matchesKey()` now correctly matches Kitty protocol sequences for unmodified letter keys
1914
- - Crash when pasting text with trailing whitespace exceeding terminal width through Markdown rendering
1915
-
1916
- ## [3.32.0] - 2026-01-08
1917
-
1918
- ### Fixed
1919
-
1920
- - Fixed text wrapping allowing long whitespace tokens to exceed line width
1921
-
1922
- ## [3.20.0] - 2026-01-06
1923
-
1924
- ### Added
1925
-
1926
- - Added `isCapsLock` helper function for detecting Caps Lock key press via Kitty protocol
1927
- - Added `isCtrlY` helper function for detecting Ctrl+Y keyboard input
1928
- - Added configurable editor keybindings with typed key identifiers and action matching
1929
- - Added word-wrapped editor rendering for long lines
1930
-
1931
- ### Changed
1932
-
1933
- - Settings list descriptions now wrap to the available width instead of truncating
1934
-
1935
- ### Fixed
1936
-
1937
- - Fixed Shift+Enter detection in legacy terminals that send ESC+CR sequence
1938
-
1939
- ## [3.15.1] - 2026-01-05
1940
-
1941
- ### Fixed
1942
-
1943
- - Fixed editor cursor blinking by allowing terminal cursor positioning when enabled.
1944
-
1945
- ## [3.15.0] - 2026-01-05
1946
-
1947
- ### Added
1948
-
1949
- - Added `inputCursor` symbol for customizing the text input cursor character
1950
- - Added `symbols` property to `EditorTheme`, `MarkdownTheme`, and `SelectListTheme` interfaces for component-level symbol customization
1951
- - Added `SymbolTheme` interface for customizing UI symbols including cursors, borders, spinners, and box-drawing characters
1952
- - Added support for custom spinner frames in the Loader component
1953
-
1954
- ## [3.9.1337] - 2026-01-04
1955
-
1956
- ### Added
1957
-
1958
- - Added `setTopBorder()` method to Editor component for displaying custom status content in the top border
1959
- - Added `getWidth()` method to TUI class for retrieving terminal width
1960
- - Added rounded corner box-drawing characters to Editor component borders
1961
-
1962
- ### Changed
1963
-
1964
- - Changed Editor component to use proper box borders with vertical side borders instead of horizontal-only borders
1965
- - Changed cursor style from block to thin blinking bar (▏) at end of line
1966
-
1967
- ## [1.500.0] - 2026-01-03
1968
-
1969
- ### Added
1970
-
1971
- - Added `getText()` method to Text component for retrieving current text content
1972
-
1973
- ## [1.337.1] - 2026-01-02
1974
-
1975
- ### Added
1976
-
1977
- - TabBar component for horizontal tab navigation
1978
- - Emergency terminal restore to prevent corrupted state on crashes
1979
- - Overhauled UI with welcome screen and powerline footer
1980
- - Theme-configurable HTML export colors
1981
- - `ctx.ui.theme` getter for styling status text with theme colors
1982
-
1983
- ### Changed
1984
-
1985
- - Forked to @linxiraos scope with unified versioning across all packages
1986
-
1987
- ### Fixed
1988
-
1989
- - Strip OSC 8 hyperlink sequences in `visibleWidth()`
1990
- - Crash on Unicode format characters in `visibleWidth()`
1991
- - Markdown code block syntax highlighting
1992
-
1993
- ## [1.337.0] - 2026-01-02
1994
-
1995
- Initial release under @linxiraos scope. See previous releases at [badlogic/pi-mono](https://github.com/badlogic/pi-mono).
1996
-
1997
- ## [1.5.0] - 2026-01-03
1998
-
1999
- ### Added
2000
-
2001
- - Added `getText()` method to Text component for retrieving current text content
2002
-
2003
- ## [1.0.1] - 2026-08-14
2004
-
2005
- - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
2006
-
2007
- ## [1.0.0] - 2026-08-13
2008
-
2009
- ### Changed
2010
-
2011
- - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
2012
-
2013
- ## [0.50.0] - 2026-01-26
2014
-
2015
- ### Added
2016
-
2017
- - Added `fullRedraws` readonly property to TUI class for tracking full screen redraws
2018
- - Added `PI_TUI_WRITE_LOG` environment variable to capture raw ANSI output for debugging
2019
-
2020
- ### Fixed
2021
-
2022
- - Fixed appended lines not being committed to scrollback, causing earlier content to be overwritten when viewport fills ([#954](https://github.com/badlogic/pi-mono/issues/954))
2023
- - Slash command menu now only triggers when the editor input is otherwise empty ([#904](https://github.com/badlogic/pi-mono/issues/904))
2024
- - Center-anchored overlays now stay vertically centered when resizing the terminal taller after a shrink ([#950](https://github.com/badlogic/pi-mono/pull/950) by [@nicobailon](https://github.com/nicobailon))
2025
- - Fixed editor multi-line insertion handling and lastAction tracking ([#945](https://github.com/badlogic/pi-mono/pull/945) by [@Perlence](https://github.com/Perlence))
2026
- - Fixed editor word wrapping to reserve a cursor column ([#934](https://github.com/badlogic/pi-mono/pull/934) by [@Perlence](https://github.com/Perlence))
2027
- - Fixed editor word wrapping to use single-pass backtracking for whitespace handling ([#924](https://github.com/badlogic/pi-mono/pull/924) by [@Perlence](https://github.com/Perlence))
2028
- - Fixed Kitty image ID allocation and cleanup to prevent image ID collisions between modules
2029
-
2030
- ## [0.49.3] - 2026-01-22
2031
-
2032
- ### Added
2033
-
2034
- - `codeBlockIndent` property on `MarkdownTheme` to customize code block content indentation (default: 2 spaces) ([#855](https://github.com/badlogic/pi-mono/pull/855) by [@terrorobe](https://github.com/terrorobe))
2035
- - Added Alt+Delete as hotkey for delete word forwards ([#878](https://github.com/badlogic/pi-mono/pull/878) by [@Perlence](https://github.com/Perlence))
2036
-
2037
- ### Changed
2038
-
2039
- - Fuzzy matching now scores consecutive matches higher and penalizes gaps more heavily for better relevance ([#860](https://github.com/badlogic/pi-mono/pull/860) by [@mitsuhiko](https://github.com/mitsuhiko))
2040
-
2041
- ### Fixed
2042
-
2043
- - Autolinked emails no longer display redundant `(mailto:...)` suffix in markdown output ([#888](https://github.com/badlogic/pi-mono/pull/888) by [@terrorobe](https://github.com/terrorobe))
2044
- - Fixed viewport tracking and cursor positioning for overlays and content shrink scenarios
2045
- - Autocomplete now allows searches with `/` characters (e.g., `folder1/folder2`) ([#882](https://github.com/badlogic/pi-mono/pull/882) by [@richardgill](https://github.com/richardgill))
2046
- - Directory completions for `@` file attachments no longer add trailing space, allowing continued autocomplete into subdirectories
2047
-
2048
- ## [0.49.1] - 2026-01-18
2049
-
2050
- ### Added
2051
-
2052
- - Added undo support to Editor with Ctrl+- hotkey. Undo coalesces consecutive word characters into one unit (fish-style). ([#831](https://github.com/badlogic/pi-mono/pull/831) by [@Perlence](https://github.com/Perlence))
2053
- - Added legacy terminal support for Ctrl+symbol keys (Ctrl+\, Ctrl+], Ctrl+-) and their Ctrl+Alt variants. ([#831](https://github.com/badlogic/pi-mono/pull/831) by [@Perlence](https://github.com/Perlence))
2054
-
2055
- ## [0.49.0] - 2026-01-17
2056
-
2057
- ### Added
2058
-
2059
- - Added `showHardwareCursor` getter and setter to control cursor visibility while keeping IME positioning active. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
2060
- - Added Emacs-style kill ring editing with yank and yank-pop keybindings. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
2061
- - Added legacy Alt+letter handling and Alt+D delete word forward support in the editor keymap. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
2062
-
2063
- ## [0.48.0] - 2026-01-16
2064
-
2065
- ### Added
2066
-
2067
- - `EditorOptions` with optional `paddingX` for horizontal content padding, plus `getPaddingX()`/`setPaddingX()` methods ([#791](https://github.com/badlogic/pi-mono/pull/791) by [@ferologics](https://github.com/ferologics))
2068
-
2069
- ### Changed
2070
-
2071
- - Hardware cursor is now disabled by default for better terminal compatibility. Set `PI_HARDWARE_CURSOR=1` to enable (replaces `PI_NO_HARDWARE_CURSOR=1` which disabled it).
2072
-
2073
- ### Fixed
2074
-
2075
- - Decode Kitty CSI-u printable sequences in the editor so shifted symbol keys (e.g., `@`, `?`) work in terminals that enable Kitty keyboard protocol ([#779](https://github.com/badlogic/pi-mono/pull/779) by [@iamd3vil](https://github.com/iamd3vil))
2076
-
2077
- ## [0.47.0] - 2026-01-16
2078
-
2079
- ### Breaking Changes
2080
-
2081
- - `Editor` constructor now requires `TUI` as first parameter: `new Editor(tui, theme)`. This enables automatic vertical scrolling when content exceeds terminal height. ([#732](https://github.com/badlogic/pi-mono/issues/732))
2082
-
2083
- ### Added
2084
-
2085
- - Hardware cursor positioning for IME support in `Editor` and `Input` components. The terminal cursor now follows the text cursor position, enabling proper IME candidate window placement for CJK input. ([#719](https://github.com/badlogic/pi-mono/pull/719))
2086
- - `Focusable` interface for components that need hardware cursor positioning. Implement `focused: boolean` and emit `CURSOR_MARKER` in render output when focused.
2087
- - `CURSOR_MARKER` constant and `isFocusable()` type guard exported from the package
2088
- - Editor now supports Page Up/Down keys (Fn+Up/Down on MacBook) for scrolling through large content ([#732](https://github.com/badlogic/pi-mono/issues/732))
2089
- - Expanded keymap coverage for terminal compatibility: added support for Home/End keys in tmux, additional modifier combinations, and improved key sequence parsing ([#752](https://github.com/badlogic/pi-mono/pull/752) by [@richardgill](https://github.com/richardgill))
2090
-
2091
- ### Fixed
2092
-
2093
- - 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](https://github.com/badlogic/pi-mono/issues/732))
2094
- - `visibleWidth()` and `extractAnsiCode()` now handle APC escape sequences (`ESC _ ... BEL`), fixing width calculation and string slicing for strings containing cursor markers
2095
- - SelectList now handles multi-line descriptions by replacing newlines with spaces ([#728](https://github.com/badlogic/pi-mono/pull/728) by [@richardgill](https://github.com/richardgill))
2096
-
2097
- ## [0.46.0] - 2026-01-15
2098
-
2099
- ### Fixed
2100
-
2101
- - 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](https://github.com/badlogic/pi-mono/pull/718) by [@dannote](https://github.com/dannote))
2102
-
2103
- ## [0.45.6] - 2026-01-13
2104
-
2105
- ### Added
2106
-
2107
- - `OverlayOptions` API for overlay positioning and sizing with CSS-like values: `width`, `maxHeight`, `row`, `col` accept numbers (absolute) or percentage strings (e.g., `"50%"`). Also supports `minWidth`, `anchor`, `offsetX`, `offsetY`, `margin`. ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2108
- - `OverlayOptions.visible` callback for responsive overlays - receives terminal dimensions, return false to hide ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2109
- - `showOverlay()` now returns `OverlayHandle` with `hide()`, `setHidden(boolean)`, `isHidden()` for programmatic visibility control ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2110
- - New exported types: `OverlayAnchor`, `OverlayHandle`, `OverlayMargin`, `OverlayOptions`, `SizeValue` ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2111
- - `truncateToWidth()` now accepts optional `pad` parameter to pad result with spaces to exactly `maxWidth` ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2112
-
2113
- ### Fixed
2114
-
2115
- - Overlay compositing crash when rendered lines exceed terminal width due to complex ANSI/OSC sequences (e.g., hyperlinks in subagent output) ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
2116
-
2117
- ## [0.44.0] - 2026-01-12
2118
-
2119
- ### Added
2120
-
2121
- - `SettingsListOptions` with `enableSearch` for fuzzy filtering in `SettingsList` ([#643](https://github.com/badlogic/pi-mono/pull/643) by [@ninlds](https://github.com/ninlds))
2122
- - `pageUp` and `pageDown` key support with `selectPageUp`/`selectPageDown` editor actions ([#662](https://github.com/badlogic/pi-mono/pull/662) by [@aliou](https://github.com/aliou))
2123
-
2124
- ### Fixed
2125
-
2126
- - Numbered list items showing "1." for all items when code blocks break list continuity ([#660](https://github.com/badlogic/pi-mono/pull/660) by [@ogulcancelik](https://github.com/ogulcancelik))
2127
-
2128
- ## [0.43.0] - 2026-01-11
2129
-
2130
- ### Added
2131
-
2132
- - `fuzzyFilter()` and `fuzzyMatch()` utilities for fuzzy text matching
2133
- - Slash command autocomplete now uses fuzzy matching instead of prefix matching
2134
-
2135
- ### Fixed
2136
-
2137
- - Cursor now moves to end of content on exit, preventing status line from being overwritten ([#629](https://github.com/badlogic/pi-mono/pull/629) by [@tallshort](https://github.com/tallshort))
2138
- - Reset ANSI styles after each rendered line to prevent style leakage
2139
-
2140
- ## [0.42.5] - 2026-01-11
2141
-
2142
- ### Fixed
2143
-
2144
- - Reduced flicker by only re-rendering changed lines ([#617](https://github.com/badlogic/pi-mono/pull/617) by [@ogulcancelik](https://github.com/ogulcancelik))
2145
- - Cursor position tracking when content shrinks with unchanged remaining lines
2146
- - TUI renders with wrong dimensions after suspend/resume if terminal was resized while suspended ([#599](https://github.com/badlogic/pi-mono/issues/599))
2147
- - Pasted content containing Kitty key release patterns (e.g., `:3F` in MAC addresses) was incorrectly filtered out ([#623](https://github.com/badlogic/pi-mono/pull/623) by [@ogulcancelik](https://github.com/ogulcancelik))
2148
-
2149
- ## [0.39.0] - 2026-01-08
2150
-
2151
- ### Added
2152
-
2153
- - **Experimental:** Overlay compositing for `ctx.ui.custom()` with `{ overlay: true }` option ([#558](https://github.com/badlogic/pi-mono/pull/558) by [@nicobailon](https://github.com/nicobailon))
2154
-
2155
- ## [0.38.0] - 2026-01-08
2156
-
2157
- ### Added
2158
-
2159
- - `EditorComponent` interface for custom editor implementations
2160
- - `StdinBuffer` class to split batched stdin into individual sequences (adapted from [OpenTUI](https://github.com/anomalyco/opentui), MIT license)
2161
-
2162
- ### Fixed
2163
-
2164
- - Key presses no longer dropped when batched with other events over SSH ([#538](https://github.com/badlogic/pi-mono/pull/538))
2165
-
2166
- ## [0.37.8] - 2026-01-07
2167
-
2168
- ### Added
2169
-
2170
- - `Component.wantsKeyRelease` property to opt-in to key release events (default false)
2171
-
2172
- ### Fixed
2173
-
2174
- - TUI now filters out key release events by default, preventing double-processing of keys in editors and other components
2175
-
2176
- ## [0.37.7] - 2026-01-07
2177
-
2178
- ### Fixed
2179
-
2180
- - `matchesKey()` now correctly matches Kitty protocol sequences for unmodified letter keys (needed for key release events)
2181
-
2182
- ## [0.37.6] - 2026-01-06
2183
-
2184
- ### Added
2185
-
2186
- - Kitty keyboard protocol flag 2 support for key release events. New exports: `isKeyRelease(data)`, `isKeyRepeat(data)`, `KeyEventType` type. Terminals supporting Kitty protocol (Kitty, Ghostty, WezTerm) now send proper key-up events.
2187
-
2188
- ## [0.37.0] - 2026-01-05
2189
-
2190
- ### Fixed
2191
-
2192
- - Crash when pasting text with trailing whitespace exceeding terminal width through Markdown rendering ([#457](https://github.com/badlogic/pi-mono/pull/457) by [@robinwander](https://github.com/robinwander))
2193
-
2194
- ## [0.34.1] - 2026-01-04
2195
-
2196
- ### Added
2197
-
2198
- - Symbol key support in keybinding system: `SymbolKey` type with 32 symbol keys, `Key` constants (e.g., `Key.backtick`, `Key.comma`), updated `matchesKey()` and `parseKey()` to handle symbol input ([#450](https://github.com/badlogic/pi-mono/pull/450) by [@kaofelix](https://github.com/kaofelix))
2199
-
2200
- ## [0.34.0] - 2026-01-04
2201
-
2202
- ### Added
2203
-
2204
- - `Editor.getExpandedText()` method that returns text with paste markers expanded to their actual content ([#444](https://github.com/badlogic/pi-mono/pull/444) by [@aliou](https://github.com/aliou))
2205
-
2206
- ## [0.33.0] - 2026-01-04
2207
-
2208
- ### Breaking Changes
2209
-
2210
- - **Key detection functions removed**: All `isXxx()` key detection functions (`isEnter()`, `isEscape()`, `isCtrlC()`, etc.) have been removed. Use `matchesKey(data, keyId)` instead (e.g., `matchesKey(data, "enter")`, `matchesKey(data, "ctrl+c")`). This affects hooks and custom tools that use `ctx.ui.custom()` with keyboard input handling. ([#405](https://github.com/badlogic/pi-mono/pull/405))
2211
-
2212
- ### Added
2213
-
2214
- - `Editor.insertTextAtCursor(text)` method for programmatic text insertion ([#419](https://github.com/badlogic/pi-mono/issues/419))
2215
- - `EditorKeybindingsManager` for configurable editor keybindings. Components now use `matchesKey()` and keybindings manager instead of individual `isXxx()` functions. ([#405](https://github.com/badlogic/pi-mono/pull/405) by [@hjanuschka](https://github.com/hjanuschka))
2216
-
2217
- ### Changed
2218
-
2219
- - Key detection refactored: consolidated `is*()` functions into generic `matchesKey(data, keyId)` function that accepts key identifiers like `"ctrl+c"`, `"shift+enter"`, `"alt+left"`, etc.
2220
-
2221
- ## [0.32.2] - 2026-01-03
2222
-
2223
- ### Fixed
2224
-
2225
- - Slash command autocomplete now triggers for commands starting with `.`, `-`, or `_` (e.g., `/.land`, `/-foo`) ([#422](https://github.com/badlogic/pi-mono/issues/422))
2226
-
2227
- ## [0.32.0] - 2026-01-03
2228
-
2229
- ### Changed
2230
-
2231
- - Editor component now uses word wrapping instead of character-level wrapping for better readability ([#382](https://github.com/badlogic/pi-mono/pull/382) by [@nickseelert](https://github.com/nickseelert))
2232
-
2233
- ### Fixed
2234
-
2235
- - Shift+Space, Shift+Backspace, and Shift+Delete now work correctly in Kitty-protocol terminals (Kitty, WezTerm, etc.) instead of being silently ignored ([#411](https://github.com/badlogic/pi-mono/pull/411) by [@nathyong](https://github.com/nathyong))
2236
-
2237
- ## [0.31.1] - 2026-01-02
2238
-
2239
- ### Fixed
2240
-
2241
- - `visibleWidth()` now strips OSC 8 hyperlink sequences, fixing text wrapping for clickable links ([#396](https://github.com/badlogic/pi-mono/pull/396) by [@Cursivez](https://github.com/Cursivez))
2242
-
2243
- ## [0.31.0] - 2026-01-02
2244
-
2245
- ### Added
2246
-
2247
- - `isShiftCtrlO()` key detection function for Shift+Ctrl+O (Kitty protocol)
2248
- - `isShiftCtrlD()` key detection function for Shift+Ctrl+D (Kitty protocol)
2249
- - `TUI.onDebug` callback for global debug key handling (Shift+Ctrl+D)
2250
- - `wrapTextWithAnsi()` utility now exported (wraps text to width, preserving ANSI codes)
2251
-
2252
- ### Changed
2253
-
2254
- - README.md completely rewritten with accurate component documentation, theme interfaces, and examples
2255
- - `visibleWidth()` reimplemented with grapheme-based width calculation, 10x faster on Bun and ~15% faster on Node ([#369](https://github.com/badlogic/pi-mono/pull/369) by [@nathyong](https://github.com/nathyong))
2256
-
2257
- ### Fixed
2258
-
2259
- - Markdown component now renders HTML tags as plain text instead of silently dropping them ([#359](https://github.com/badlogic/pi-mono/issues/359))
2260
- - Crash in `visibleWidth()` and grapheme iteration when encountering undefined code points ([#372](https://github.com/badlogic/pi-mono/pull/372) by [@HACKE-RC](https://github.com/HACKE-RC))
2261
- - ZWJ emoji sequences (rainbow flag, family, etc.) now render with correct width instead of being split into multiple characters ([#369](https://github.com/badlogic/pi-mono/pull/369) by [@nathyong](https://github.com/nathyong))
2262
-
2263
- ## [0.29.0] - 2025-12-25
2264
-
2265
- ### Added
2266
-
2267
- - **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](https://github.com/badlogic/pi-mono/pull/307) by [@mitsuhiko](https://github.com/mitsuhiko))
2268
- - **Word navigation for Input component**: Added Ctrl+Left/Right and Alt+Left/Right support for word-by-word cursor movement. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
2269
- - **Full Unicode input**: Input component now accepts Unicode characters beyond ASCII. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
2270
-
2271
- ### Fixed
2272
-
2273
- - **Readline-style Ctrl+W**: Now skips trailing whitespace before deleting the preceding word, matching standard readline behavior. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))