@oh-my-pi/pi-tui 15.7.6 → 15.8.2

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.
package/CHANGELOG.md CHANGED
@@ -2,14 +2,51 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [15.7.6] - 2026-06-01
5
+ ## [15.8.2] - 2026-06-03
6
+
7
+ ### Added
8
+
9
+ - 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)).
6
10
 
7
11
  ### Fixed
8
12
 
9
- - 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.
13
+ - 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.
14
+ - 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.
15
+ - 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)).
16
+ - 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.
17
+ - 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.
18
+ - 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.
19
+ - 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.
20
+ - 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.
21
+ - 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)).
22
+ - 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.
23
+ - 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)).
24
+ - Fixed width-shrink reflow leaving old-width rows in native history so later appends no longer undercount scrollback growth or duplicate wrapped content.
25
+ - Fixed hiding overlays after terminal reflow so stale dialog rows are scrubbed from native scrollback on non-multiplexer terminals.
26
+
27
+ ### Removed
28
+
29
+ - 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`.
30
+
31
+ ## [15.8.1] - 2026-06-02
10
32
 
11
33
  ### Fixed
12
34
 
35
+ - 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)).
36
+
37
+ ## [15.8.0] - 2026-06-02
38
+
39
+ ### Fixed
40
+
41
+ - 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)).
42
+ - 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)).
43
+ - 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.
44
+
45
+ ## [15.7.6] - 2026-06-01
46
+
47
+ ### Fixed
48
+
49
+ - 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.
13
50
  - 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))
14
51
 
15
52
  ## [15.7.5] - 2026-06-01
@@ -50,6 +87,7 @@
50
87
  - 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))
51
88
 
52
89
  ## [15.6.0] - 2026-05-30
90
+
53
91
  ### Added
54
92
 
55
93
  - Added autocomplete triggering for internal URL scheme tokens such as `local://` and `skill://` while typing in the editor
@@ -96,6 +134,7 @@
96
134
  - Fixed full TUI redraws clearing terminal scrollback with `CSI 3 J`, preserving manual scrollback inspection while active sessions continue updating. ([#1295](https://github.com/can1357/oh-my-pi/issues/1295))
97
135
 
98
136
  ## [15.2.3] - 2026-05-22
137
+
99
138
  ### Added
100
139
 
101
140
  - Added `SettingsList#setItems` to replace the entire settings list with a new items array while automatically clamping selection to a valid index
@@ -123,6 +162,7 @@
123
162
  - Restored the `Key` runtime helper on `@oh-my-pi/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.
124
163
 
125
164
  ## [15.0.1] - 2026-05-14
165
+
126
166
  ### Breaking Changes
127
167
 
128
168
  - Increased the minimum required Bun version for the TUI package from >=1.3.7 to >=1.3.14
@@ -156,6 +196,10 @@
156
196
  - `SlashCommand.getArgumentCompletions()` may return a `Promise`; results are now awaited and non-array returns are ignored (ports pi-mono `a1e10789`)
157
197
  - Fuzzy `@` autocomplete now follows symlinked directories via `ScanOptions.follow_links` plumbed through the native walker (ports pi-mono `780d5367`)
158
198
  - 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`)
199
+ - Changed slash-command autocomplete list rendering to combine command hint and description in a single displayed suggestion text
200
+ - Changed render scheduling to throttle `requestRender` calls to roughly 60fps by batching updates
201
+ - Changed terminal input handling to process complete cell-size responses without buffering partial input
202
+ - Changed `KeyId` to accept super-modifier combinations and improve typed key-id validation
159
203
 
160
204
  ### Fixed
161
205
 
@@ -171,20 +215,11 @@
171
215
  - Allowed `SlashCommand.getArgumentCompletions` to return asynchronous results by accepting Promise-based completions
172
216
  - Added `argumentHint` support to slash command definitions and displayed it in command suggestion descriptions
173
217
  - Added support for xterm `modifyOtherKeys` printable key sequences by decoding `CSI 27;mod;key~` into text input
174
-
175
- ### Changed
176
-
177
- - Changed slash-command autocomplete list rendering to combine command hint and description in a single displayed suggestion text
178
- - Changed render scheduling to throttle `requestRender` calls to roughly 60fps by batching updates
179
- - Changed terminal input handling to process complete cell-size responses without buffering partial input
180
- - Changed `KeyId` to accept super-modifier combinations and improve typed key-id validation
181
-
182
- ### Fixed
183
-
184
218
  - Normalized line output during rendering to correct Thai/Lao AM glyph composition for displayed text
185
219
  - Fixed duplicated Kitty key input emissions by dropping the matching unmodified follow-up sequence after a Kitty CSI-u printable-key event
186
220
 
187
221
  ## [14.9.5] - 2026-05-12
222
+
188
223
  ### Fixed
189
224
 
190
225
  - 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))
@@ -238,6 +273,7 @@
238
273
  - Autocomplete fuzzy discovery now accepts optional SearchDb instance for faster searches
239
274
 
240
275
  ## [13.16.0] - 2026-03-27
276
+
241
277
  ### Changed
242
278
 
243
279
  - Updated tab replacement in editor text sanitization to respect configured tab width setting
@@ -253,6 +289,7 @@
253
289
  - Fixed editor consuming user-rebound copy keys, preventing custom keybindings from working in the editor
254
290
 
255
291
  ## [13.14.1] - 2026-03-21
292
+
256
293
  ### Added
257
294
 
258
295
  - Added Ctrl+_ as an additional default shortcut for undo
@@ -273,17 +310,20 @@
273
310
  - Fixed paste marker expansion to handle special regex replacement tokens ($1, $2, $&, $$, $`, $') literally in pasted content
274
311
 
275
312
  ## [13.11.0] - 2026-03-12
313
+
276
314
  ### Fixed
277
315
 
278
316
  - Fixed OSC 11 background color detection to correctly handle partial escape sequences that arrive mid-buffer, preventing user input from being swallowed
279
317
  - Fixed race condition where overlapping OSC 11 queries would be incorrectly cancelled by DA1 sentinels from previous queries
280
318
 
281
319
  ## [13.7.5] - 2026-03-04
320
+
282
321
  ### Changed
283
322
 
284
323
  - Extracted word navigation logic into reusable `moveWordLeft` and `moveWordRight` utility functions for consistent cursor movement across components
285
324
 
286
325
  ## [13.6.2] - 2026-03-03
326
+
287
327
  ### Fixed
288
328
 
289
329
  - Fixed cursor positioning when content shrinks to empty without clearOnShrink enabled
@@ -293,6 +333,7 @@
293
333
  ### Fixed
294
334
 
295
335
  - 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))
336
+
296
337
  ## [13.5.3] - 2026-03-01
297
338
 
298
339
  ### Fixed
@@ -302,6 +343,7 @@
302
343
  - Fixed cursor positioning instability when appending content under external cursor relocation by using absolute screen addressing instead of relative cursor movement
303
344
 
304
345
  ## [13.5.2] - 2026-03-01
346
+
305
347
  ### Breaking Changes
306
348
 
307
349
  - Removed `getMermaidImage` callback from MarkdownTheme; replaced with `getMermaidAscii` that accepts ASCII string instead of image data
@@ -312,6 +354,7 @@
312
354
  - Mermaid diagrams now render as ASCII text instead of terminal graphics protocol images
313
355
 
314
356
  ## [13.5.1] - 2026-03-01
357
+
315
358
  ### Fixed
316
359
 
317
360
  - Fixed viewport shift handling to prevent stale content when mixed updates remap screen rows
@@ -339,6 +382,7 @@
339
382
 
340
383
  - 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).
341
384
  - Fixed scroll overshoot on `stop()` when content fills the viewport by clamping target row movement to valid screen rows.
385
+
342
386
  ## [13.4.0] - 2026-03-01
343
387
 
344
388
  ### Added
@@ -360,6 +404,7 @@
360
404
  - 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.
361
405
 
362
406
  ## [13.3.8] - 2026-02-28
407
+
363
408
  ### Breaking Changes
364
409
 
365
410
  - Changed mermaid hash type from string to bigint in `getMermaidImage` callback and `extractMermaidBlocks` return type
@@ -381,6 +426,7 @@
381
426
  - Fixed stale viewport rows appearing when terminal height increases by triggering full re-render on height changes
382
427
 
383
428
  ## [12.18.0] - 2026-02-21
429
+
384
430
  ### Fixed
385
431
 
386
432
  - Fixed viewport synchronization issue by clearing scrollback when terminal state becomes desynced during full re-renders
@@ -409,18 +455,21 @@
409
455
  - Fixed incremental stale-row clearing to use erase-below semantics in synchronized output, reducing leftover-line artifacts after shrink operations.
410
456
 
411
457
  ## [12.9.0] - 2026-02-17
458
+
412
459
  ### Added
413
460
 
414
461
  - Exported `getTerminalId()` function to get a stable identifier for the current terminal, with support for TTY device paths and terminal multiplexers
415
462
  - Exported `getTtyPath()` function to resolve the TTY device path for stdin via POSIX `ttyname(3)`
416
463
 
417
464
  ## [12.5.0] - 2026-02-15
465
+
418
466
  ### Added
419
467
 
420
468
  - Added `cursorOverride` and `cursorOverrideWidth` properties to customize the end-of-text cursor glyph with ANSI-styled strings
421
469
  - Added `getUseTerminalCursor()` method to query the terminal cursor mode setting
422
470
 
423
471
  ## [11.10.0] - 2026-02-10
472
+
424
473
  ### Added
425
474
 
426
475
  - Added `hint` property to autocomplete items to display dim ghost text after cursor when item is selected
@@ -433,6 +482,7 @@
433
482
  - Updated editor to render inline hint text as dim ghost text after cursor when autocomplete suggestions are active or provider supplies hints
434
483
 
435
484
  ## [11.8.0] - 2026-02-10
485
+
436
486
  ### Added
437
487
 
438
488
  - Added Alt+Y keybinding to cycle through kill ring entries (yank-pop)
@@ -449,6 +499,7 @@
449
499
  - Changed undo coalescing in Input component to group consecutive word typing into single undo units
450
500
 
451
501
  ## [11.4.1] - 2026-02-06
502
+
452
503
  ### Fixed
453
504
 
454
505
  - Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of blank lines from being output
@@ -541,6 +592,7 @@
541
592
  - Fixed handling of private use Unicode codepoints (U+E000 to U+F8FF) in Kitty key decoding to prevent invalid character interpretation
542
593
 
543
594
  ## [9.7.0] - 2026-02-01
595
+
544
596
  ### Breaking Changes
545
597
 
546
598
  - Removed `Key` helper object from public API; use string literals like `"ctrl+c"` instead of `Key.ctrl("c")`
@@ -552,6 +604,7 @@
552
604
  - Simplified `isKeyRelease()` and `isKeyRepeat()` to use regex pattern matching instead of string inclusion checks
553
605
 
554
606
  ## [9.6.2] - 2026-02-01
607
+
555
608
  ### Changed
556
609
 
557
610
  - Renamed `EllipsisKind` enum to `Ellipsis` for clearer API naming
@@ -565,6 +618,7 @@
565
618
  - Removed `extractAnsiCode` function from public API
566
619
 
567
620
  ## [9.6.1] - 2026-02-01
621
+
568
622
  ### Changed
569
623
 
570
624
  - Improved performance of key ID parsing with optimized cache lookup strategy
@@ -575,12 +629,14 @@
575
629
  - Removed `visibleWidth` benchmark file in favor of Kitty sequence benchmarking
576
630
 
577
631
  ## [9.5.0] - 2026-02-01
632
+
578
633
  ### Changed
579
634
 
580
635
  - Improved fuzzy file search performance by using native implementation instead of spawning external process
581
636
  - Replaced external `fd` binary with native fuzzy path search for `@`-prefixed autocomplete
582
637
 
583
638
  ## [9.4.0] - 2026-01-31
639
+
584
640
  ### Added
585
641
 
586
642
  - Exported `padding` utility function for creating space-padded strings efficiently
@@ -592,59 +648,74 @@
592
648
  ## [9.2.2] - 2026-01-31
593
649
 
594
650
  ### Added
651
+
595
652
  - Added setAutocompleteMaxVisible() configuration (3-20 items)
596
653
  - Added image detection to terminal capabilities (containsImage method)
597
654
  - Added stdin monitoring to detect stalled input events and log warnings
598
655
 
599
656
  ### Changed
657
+
600
658
  - Improved blockquote rendering with text wrapping in Markdown component
601
659
  - Restructured terminal capabilities from interface-based to class-based model
602
660
  - Improved table column width calculation with word-aware wrapping
603
661
  - Refactored text utilities to use native WASM implementations for strings >256 chars with JS fast path
604
662
 
605
663
  ### Fixed
664
+
606
665
  - Simplified terminal write error handling to mark terminal as dead on any write failure
607
666
  - Fixed multi-line strings in renderOutputBlock causing width overflow
608
667
  - Fixed slash command autocomplete applying stale completion when typing quickly
609
668
 
610
669
  ### Removed
670
+
611
671
  - Removed TUI layout engine exports from public API (BoxNode, ColumnNode, LayoutNode, etc.)
612
672
 
613
673
  ## [8.12.7] - 2026-01-29
614
674
 
615
675
  ### Fixed
676
+
616
677
  - Fixed slash command autocomplete applying stale completion when typing quickly
617
678
 
618
679
  ## [8.4.1] - 2026-01-25
619
680
 
620
681
  ### Added
682
+
621
683
  - Added fuzzy match function for autocomplete suggestions
684
+
622
685
  ## [8.4.0] - 2026-01-25
623
686
 
624
687
  ### Changed
688
+
625
689
  - Added Ctrl+Backspace as a delete-word-backward keybinding and improved modified backspace matching
626
690
 
627
691
  ### Fixed
692
+
628
693
  - Terminal gracefully handles write failures by marking dead instead of exiting the process
629
694
  - Reserved cursor space for zero padding and corrected end-of-line cursor rendering to prevent wrap glitches
630
695
  - Corrected editor end-of-line cursor rendering assertion to use includes() instead of endsWith()
696
+
631
697
  ## [8.2.0] - 2026-01-24
632
698
 
633
699
  ### Added
700
+
634
701
  - Added mermaid diagram rendering engine (renderMermaidToPng) with mmdc CLI integration
635
702
  - Added terminal graphics encoding (iTerm2/Kitty) for mermaid diagrams with automatic width scaling
636
703
  - Added mermaid block extraction and deduplication utilities (extractMermaidBlocks)
637
704
 
638
705
  ### Changed
706
+
639
707
  - Updated TypeScript configuration for better publish-time configuration handling with tsconfig.publish.json
640
708
  - Migrated file system operations from synchronous to asynchronous APIs in autocomplete provider for non-blocking I/O
641
709
  - Migrated node module imports from named to namespace imports across all packages for consistency with project guidelines
642
710
 
643
711
  ### Fixed
712
+
644
713
  - Fixed crash when terminal becomes unavailable (EIO errors) by exiting gracefully instead of throwing
645
714
  - Fixed potential errors during emergency terminal restore when terminal is already dead
646
715
  - Fixed autocomplete race condition by tracking request ID to prevent stale suggestion results
716
+
647
717
  ## [6.8.3] - 2026-01-21
718
+
648
719
  ### Added
649
720
 
650
721
  - Added undo support in the editor via `Ctrl+-`
@@ -700,6 +771,7 @@
700
771
  - Fixed Alt+letter key combinations for better recognition
701
772
 
702
773
  ## [5.3.1] - 2026-01-15
774
+
703
775
  ### Fixed
704
776
 
705
777
  - Fixed rendering issues on Windows by preventing re-entrant renders
@@ -729,27 +801,32 @@
729
801
  ## [4.7.0] - 2026-01-12
730
802
 
731
803
  ### Fixed
804
+
732
805
  - Remove trailing space padding from Text, Markdown, and TruncatedText components when no background color is set (fixes copied text including unwanted whitespace)
733
806
 
734
807
  ## [4.6.0] - 2026-01-12
735
808
 
736
809
  ### Added
810
+
737
811
  - Add fuzzy matching module (`fuzzyMatch`, `fuzzyFilter`) for command autocomplete
738
812
  - Add `getExpandedText()` to editor for expanding paste markers
739
813
  - Add backslash+enter newline fallback for terminals without Kitty protocol
740
814
 
741
815
  ### Fixed
816
+
742
817
  - Remove Kitty protocol query timeout that caused shift+enter delays
743
818
  - Add bracketed paste check to prevent false key release/repeat detection
744
819
  - Rendering optimizations: only re-render changed lines
745
820
  - Refactor input component to use keybindings manager
746
821
 
747
822
  ## [4.4.4] - 2026-01-11
823
+
748
824
  ### Fixed
749
825
 
750
826
  - Fixed Ctrl+Enter sequences to insert new lines in the editor
751
827
 
752
828
  ## [4.2.1] - 2026-01-11
829
+
753
830
  ### Changed
754
831
 
755
832
  - Improved file autocomplete to show directory listing when typing `@` with no query, and fall back to prefix matching when fuzzy search returns no results
@@ -760,11 +837,13 @@
760
837
  - Fixed `fd` tool detection to automatically find `fd` or `fdfind` in PATH when not explicitly configured
761
838
 
762
839
  ## [4.1.0] - 2026-01-10
840
+
763
841
  ### Added
764
842
 
765
843
  - Added persistent prompt history storage support via `setHistoryStorage()` method, allowing history to be saved and restored across sessions
766
844
 
767
845
  ## [4.0.0] - 2026-01-10
846
+
768
847
  ### Added
769
848
 
770
849
  - `EditorComponent` interface for custom editor implementations
@@ -795,6 +874,7 @@
795
874
  - Fixed text wrapping allowing long whitespace tokens to exceed line width
796
875
 
797
876
  ## [3.20.0] - 2026-01-06
877
+
798
878
  ### Added
799
879
 
800
880
  - Added `isCapsLock` helper function for detecting Caps Lock key press via Kitty protocol
@@ -826,6 +906,7 @@
826
906
  - Added support for custom spinner frames in the Loader component
827
907
 
828
908
  ## [3.9.1337] - 2026-01-04
909
+
829
910
  ### Added
830
911
 
831
912
  - Added `setTopBorder()` method to Editor component for displaying custom status content in the top border
@@ -838,6 +919,7 @@
838
919
  - Changed cursor style from block to thin blinking bar (▏) at end of line
839
920
 
840
921
  ## [1.500.0] - 2026-01-03
922
+
841
923
  ### Added
842
924
 
843
925
  - Added `getText()` method to Text component for retrieving current text content
@@ -902,4 +984,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
902
984
 
903
985
  ### Fixed
904
986
 
905
- - **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))
987
+ - **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))
package/README.md CHANGED
@@ -513,7 +513,7 @@ The TUI uses three rendering strategies:
513
513
  2. **Width Changed or Change Above Viewport**: Clear screen and full re-render
514
514
  3. **Normal Update**: Move cursor to first changed line, clear to end, render changed lines
515
515
 
516
- All updates are wrapped in **synchronized output** (`\x1b[?2026h` ... `\x1b[?2026l`) for atomic, flicker-free rendering.
516
+ All updates are wrapped in **synchronized output** (`\x1b[?2026h` ... `\x1b[?2026l`) for atomic, flicker-free rendering unless `PI_NO_SYNC_OUTPUT=1` is set. The opt-out removes only the DEC 2026 wrapper; paint writes still guard terminal autowrap to avoid pending-wrap cursor artifacts.
517
517
 
518
518
  ## Terminal Interface
519
519
 
@@ -16,7 +16,8 @@ export declare class TerminalInfo {
16
16
  readonly trueColor: boolean;
17
17
  readonly hyperlinks: boolean;
18
18
  readonly notifyProtocol: NotifyProtocol;
19
- constructor(id: TerminalId, imageProtocol: ImageProtocol | null, trueColor: boolean, hyperlinks: boolean, notifyProtocol?: NotifyProtocol);
19
+ readonly eagerEraseScrollbackRisk: boolean;
20
+ constructor(id: TerminalId, imageProtocol: ImageProtocol | null, trueColor: boolean, hyperlinks: boolean, notifyProtocol?: NotifyProtocol, eagerEraseScrollbackRisk?: boolean);
20
21
  isImageLine(line: string): boolean;
21
22
  formatNotification(message: string): string;
22
23
  sendNotification(message: string): void;
@@ -28,6 +29,29 @@ export declare function isNotificationSuppressed(): boolean;
28
29
  * Windows Terminal introduced SIXEL support in preview 1.22.
29
30
  */
30
31
  export declare function isWindowsTerminalPreviewSixelSupported(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
32
+ /**
33
+ * Whether eager live-frame native scrollback rebuilds are unsafe when the
34
+ * terminal viewport position is unobservable.
35
+ *
36
+ * A TUI history rebuild emits xterm ED3 (`CSI 3 J`, erase saved lines). On the
37
+ * terminals below, ED3 can disturb a reader parked in native scrollback during
38
+ * streaming: kitty/ghostty/alacritty/VTE clamp the scroll offset back to the
39
+ * active tail when saved lines are erased. WezTerm, macOS Terminal.app, and
40
+ * iTerm2 expose scrollback-only clears via ED3/terminfo E3; that still
41
+ * invalidates a reader's scrollback position during live streaming.
42
+ *
43
+ * Windows Terminal erases its host scrollback on ED3 and repositions the
44
+ * viewport against the shortened buffer, so a scrolled-up reader is yanked.
45
+ * Native win32 is excluded here because the renderer guards it with dedicated
46
+ * platform checks (the viewport position is never observable on Windows — see
47
+ * `Terminal.isNativeViewportAtBottom`); a `WT_SESSION` sighting on any other
48
+ * platform means the outer host is Windows Terminal fronting a WSL distro (WT
49
+ * propagates the variable into the Linux environment), where the same ED3
50
+ * yank applies. See #1610.
51
+ *
52
+ * Pure helper for tests and `TERMINAL` trait construction. See #1682 and #1719.
53
+ */
54
+ export declare function detectTerminalEagerEraseScrollbackRisk(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
31
55
  export declare const TERMINAL_ID: TerminalId;
32
56
  export declare const TERMINAL: TerminalInfo;
33
57
  /**
@@ -30,6 +30,32 @@ export interface Terminal {
30
30
  /**
31
31
  * Returns whether the native terminal viewport is at the scrollback tail when
32
32
  * the host exposes that state. `undefined` means the terminal cannot report it.
33
+ *
34
+ * `ProcessTerminal` deliberately does not implement this — no real terminal
35
+ * can answer it truthfully:
36
+ *
37
+ * - POSIX terminals expose no scrollback-position API at all.
38
+ * - Every modern Windows terminal host (Windows Terminal, VS Code, Tabby,
39
+ * Hyper, Alacritty, WezTerm, JetBrains, …) fronts console apps through
40
+ * ConPTY, where kernel32's `GetConsoleScreenBufferInfo` describes the
41
+ * pseudo-console buffer. That buffer is pinned to the visible grid —
42
+ * scrollback lives in the host UI, invisible to console APIs
43
+ * (microsoft/terminal#10191) — so a probe reads "at bottom" no matter
44
+ * where the user scrolled. Trusting it let streaming-time rebuilds emit
45
+ * `\x1b[3J` and yank scrolled readers: #1635 (Windows Terminal), #1746
46
+ * (Tabby and other ConPTY hosts). No env var distinguishes these hosts
47
+ * (Tabby sets none), so trust cannot be conditional on the environment.
48
+ * - Legacy conhost (the only non-ConPTY host) keeps a real scrollback
49
+ * buffer, but its window follows the output cursor: a probe comparing
50
+ * `srWindow.Bottom` against `dwSize.Y - 1` reads "scrolled up" for a user
51
+ * following live output until all ~9001 buffer rows fill, permanently
52
+ * blocking checkpoint scrollback reconciliation.
53
+ *
54
+ * The renderer treats a missing implementation / `undefined` as "unknown":
55
+ * live mutations defer destructive rebuilds and reconcile native scrollback
56
+ * at explicit checkpoints (prompt submit), where the user's keystroke has
57
+ * already pinned the host viewport to the bottom. Only test terminals
58
+ * (xterm.js-backed) implement this with a real answer.
33
59
  */
34
60
  isNativeViewportAtBottom?(): boolean | undefined;
35
61
  /**
@@ -41,21 +67,6 @@ export interface Terminal {
41
67
  /** The last detected terminal appearance, or undefined if not yet known. */
42
68
  get appearance(): TerminalAppearance | undefined;
43
69
  }
44
- /**
45
- * Whether the native console viewport-position probe should be consulted.
46
- *
47
- * Returns `true` only on native Windows that is *not* fronted by Windows
48
- * Terminal. The kernel32 `GetConsoleScreenBufferInfo` API answers about the
49
- * ConPTY pseudo-console — which is always pinned to its tail — and not about
50
- * the user-visible scrollback in modern hosts. Treat any such host as
51
- * unreportable so the renderer falls back to the deferred-rebuild path.
52
- *
53
- * Pure helper for unit testing; the runtime call site reads `$env` /
54
- * `process.platform`. See #1635.
55
- */
56
- export declare function shouldTrustNativeViewportProbe(env?: {
57
- WT_SESSION?: string | undefined;
58
- }, platform?: NodeJS.Platform): boolean;
59
70
  /**
60
71
  * Real terminal using process.stdin/stdout
61
72
  */
@@ -65,20 +76,6 @@ export declare class ProcessTerminal implements Terminal {
65
76
  get appearance(): TerminalAppearance | undefined;
66
77
  onAppearanceChange(callback: (appearance: TerminalAppearance) => void): void;
67
78
  start(onInput: (data: string) => void, onResize: () => void): void;
68
- /**
69
- * Returns true when Windows' active console viewport is at the scrollback tail.
70
- * POSIX terminals do not expose native scrollback position through a standard API.
71
- *
72
- * On native Windows running under Windows Terminal (the default modern
73
- * host), the `kernel32` probe answers about the ConPTY pseudo-console — not
74
- * the user-visible WT viewport — so it would always read "at bottom" while
75
- * the user is scrolled up. Return `undefined` there so the renderer falls
76
- * back to the POSIX-style deferred-rebuild path: streaming mutations stay
77
- * non-destructive (no `\x1b[3J`), and the rebuild fires at the next prompt
78
- * checkpoint via {@link TUI.refreshNativeScrollbackIfDirty} where the user
79
- * is already pinned to the bottom by the editor keystroke. See #1635.
80
- */
81
- isNativeViewportAtBottom(): boolean | undefined;
82
79
  drainInput(maxMs?: number, idleMs?: number): Promise<void>;
83
80
  stop(): void;
84
81
  write(data: string): void;
@@ -171,9 +171,20 @@ export declare class TUI extends Container {
171
171
  * non-destructive repaint. This trades the anti-yank guarantee for a clean,
172
172
  * duplicate-free history and is meant for windows where output above the fold
173
173
  * is actively re-rendering — e.g. a tool whose result is still streaming and
174
- * re-laying-out rows that have already scrolled into history. A snap to the tail
175
- * is acceptable there. A terminal that can report a *known*-scrolled viewport
176
- * (Windows) still defers; only the unknown case is forced to rebuild.
174
+ * re-laying-out rows that have already scrolled into history. A terminal that
175
+ * reports a *known*-scrolled viewport still defers, as does native Windows
176
+ * (the viewport is never observable there and ConPTY hosts erase host
177
+ * scrollback on ED3 — #1635/#1746); only the unknown POSIX case is forced to
178
+ * rebuild. POSIX hosts known to disturb scrolled readers on xterm ED3
179
+ * (`CSI 3 J`, erase saved lines) also defer the eager opt-in; checkpoint and
180
+ * direct user-input rebuilds are unaffected.
181
+ *
182
+ * Disabling does not take effect until the next frame has been classified:
183
+ * the event batch that ends a foreground stream both removes its UI rows
184
+ * (loader/status teardown — a shrink) and clears this flag before the
185
+ * throttled render timer fires. If the flag dropped immediately, that
186
+ * teardown frame would hit the ED3-risk idle deferral and freeze on screen
187
+ * (stale spinner) until the next keystroke.
177
188
  */
178
189
  setEagerNativeScrollbackRebuild(enabled: boolean): void;
179
190
  setFocus(component: Component | null): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-tui",
4
- "version": "15.7.6",
4
+ "version": "15.8.2",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -37,8 +37,8 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@oh-my-pi/pi-natives": "15.7.6",
41
- "@oh-my-pi/pi-utils": "15.7.6",
40
+ "@oh-my-pi/pi-natives": "15.8.2",
41
+ "@oh-my-pi/pi-utils": "15.8.2",
42
42
  "lru-cache": "11.5.1",
43
43
  "marked": "^18.0.4"
44
44
  },
@@ -146,22 +146,24 @@ const DEFAULT_COLOR_SWATCH_GLYPH = "■";
146
146
  // entities like &#9731; and paths like foo#fff) and not trailed by more hex
147
147
  // (so over-long runs never produce a misleading swatch). Length/letter rules
148
148
  // are enforced in classifyHexColor since the alternation can't express "exactly
149
- // 3, 4, 6, or 8".
149
+ // 3, 6, or 8".
150
150
  const HEX_COLOR_REGEX = /(?<![\w#&])#([0-9a-fA-F]{3,8})(?![0-9a-fA-F])/g;
151
151
  const HEX_COLOR_EXACT_REGEX = /^#([0-9a-fA-F]{3,8})$/;
152
152
 
153
153
  /**
154
154
  * Decide whether a run of hex digits denotes a renderable CSS color.
155
155
  *
156
- * Only the canonical CSS lengths (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) qualify. In
157
- * `strict` mode (bare prose) a 3/4-digit run must contain a hex letter, so the
156
+ * Only the canonical CSS lengths (#RGB, #RRGGBB, #RRGGBBAA) qualify. The 4-digit
157
+ * #RGBA form is deliberately excluded: it collides with hashline `#TAG` snapshot
158
+ * tags (4 hex digits, e.g. #6C5E), which would otherwise sprout spurious swatches.
159
+ * In `strict` mode (bare prose) a 3-digit run must contain a hex letter, so the
158
160
  * far more common short issue/PR references (#123, #1011) don't sprout swatches.
159
161
  * Codespans opt out of strictness — the backticks already signal "this is a color".
160
162
  */
161
163
  function classifyHexColor(hex: string, strict: boolean): boolean {
162
164
  const n = hex.length;
163
- if (n !== 3 && n !== 4 && n !== 6 && n !== 8) return false;
164
- if (strict && n <= 4 && !/[a-fA-F]/.test(hex)) return false;
165
+ if (n !== 3 && n !== 6 && n !== 8) return false;
166
+ if (strict && n === 3 && !/[a-fA-F]/.test(hex)) return false;
165
167
  return true;
166
168
  }
167
169