@oh-my-pi/pi-tui 15.7.6 → 15.8.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.
- package/CHANGELOG.md +63 -13
- package/dist/types/terminal.d.ts +22 -0
- package/dist/types/tui.d.ts +6 -4
- package/package.json +3 -3
- package/src/components/markdown.ts +7 -5
- package/src/terminal.ts +33 -0
- package/src/tui.ts +28 -18
package/CHANGELOG.md
CHANGED
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [15.
|
|
5
|
+
## [15.8.0] - 2026-06-02
|
|
6
6
|
|
|
7
7
|
### Fixed
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- 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)).
|
|
10
|
+
- 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)).
|
|
11
|
+
- 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.
|
|
12
|
+
|
|
13
|
+
## [15.7.6] - 2026-06-01
|
|
10
14
|
|
|
11
15
|
### Fixed
|
|
12
16
|
|
|
17
|
+
- 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
18
|
- 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
19
|
|
|
15
20
|
## [15.7.5] - 2026-06-01
|
|
@@ -50,6 +55,7 @@
|
|
|
50
55
|
- 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
56
|
|
|
52
57
|
## [15.6.0] - 2026-05-30
|
|
58
|
+
|
|
53
59
|
### Added
|
|
54
60
|
|
|
55
61
|
- Added autocomplete triggering for internal URL scheme tokens such as `local://` and `skill://` while typing in the editor
|
|
@@ -96,6 +102,7 @@
|
|
|
96
102
|
- 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
103
|
|
|
98
104
|
## [15.2.3] - 2026-05-22
|
|
105
|
+
|
|
99
106
|
### Added
|
|
100
107
|
|
|
101
108
|
- Added `SettingsList#setItems` to replace the entire settings list with a new items array while automatically clamping selection to a valid index
|
|
@@ -123,6 +130,7 @@
|
|
|
123
130
|
- 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
131
|
|
|
125
132
|
## [15.0.1] - 2026-05-14
|
|
133
|
+
|
|
126
134
|
### Breaking Changes
|
|
127
135
|
|
|
128
136
|
- Increased the minimum required Bun version for the TUI package from >=1.3.7 to >=1.3.14
|
|
@@ -156,6 +164,10 @@
|
|
|
156
164
|
- `SlashCommand.getArgumentCompletions()` may return a `Promise`; results are now awaited and non-array returns are ignored (ports pi-mono `a1e10789`)
|
|
157
165
|
- Fuzzy `@` autocomplete now follows symlinked directories via `ScanOptions.follow_links` plumbed through the native walker (ports pi-mono `780d5367`)
|
|
158
166
|
- 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`)
|
|
167
|
+
- Changed slash-command autocomplete list rendering to combine command hint and description in a single displayed suggestion text
|
|
168
|
+
- Changed render scheduling to throttle `requestRender` calls to roughly 60fps by batching updates
|
|
169
|
+
- Changed terminal input handling to process complete cell-size responses without buffering partial input
|
|
170
|
+
- Changed `KeyId` to accept super-modifier combinations and improve typed key-id validation
|
|
159
171
|
|
|
160
172
|
### Fixed
|
|
161
173
|
|
|
@@ -171,20 +183,11 @@
|
|
|
171
183
|
- Allowed `SlashCommand.getArgumentCompletions` to return asynchronous results by accepting Promise-based completions
|
|
172
184
|
- Added `argumentHint` support to slash command definitions and displayed it in command suggestion descriptions
|
|
173
185
|
- 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
186
|
- Normalized line output during rendering to correct Thai/Lao AM glyph composition for displayed text
|
|
185
187
|
- Fixed duplicated Kitty key input emissions by dropping the matching unmodified follow-up sequence after a Kitty CSI-u printable-key event
|
|
186
188
|
|
|
187
189
|
## [14.9.5] - 2026-05-12
|
|
190
|
+
|
|
188
191
|
### Fixed
|
|
189
192
|
|
|
190
193
|
- 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 +241,7 @@
|
|
|
238
241
|
- Autocomplete fuzzy discovery now accepts optional SearchDb instance for faster searches
|
|
239
242
|
|
|
240
243
|
## [13.16.0] - 2026-03-27
|
|
244
|
+
|
|
241
245
|
### Changed
|
|
242
246
|
|
|
243
247
|
- Updated tab replacement in editor text sanitization to respect configured tab width setting
|
|
@@ -253,6 +257,7 @@
|
|
|
253
257
|
- Fixed editor consuming user-rebound copy keys, preventing custom keybindings from working in the editor
|
|
254
258
|
|
|
255
259
|
## [13.14.1] - 2026-03-21
|
|
260
|
+
|
|
256
261
|
### Added
|
|
257
262
|
|
|
258
263
|
- Added Ctrl+_ as an additional default shortcut for undo
|
|
@@ -273,17 +278,20 @@
|
|
|
273
278
|
- Fixed paste marker expansion to handle special regex replacement tokens ($1, $2, $&, $$, $`, $') literally in pasted content
|
|
274
279
|
|
|
275
280
|
## [13.11.0] - 2026-03-12
|
|
281
|
+
|
|
276
282
|
### Fixed
|
|
277
283
|
|
|
278
284
|
- Fixed OSC 11 background color detection to correctly handle partial escape sequences that arrive mid-buffer, preventing user input from being swallowed
|
|
279
285
|
- Fixed race condition where overlapping OSC 11 queries would be incorrectly cancelled by DA1 sentinels from previous queries
|
|
280
286
|
|
|
281
287
|
## [13.7.5] - 2026-03-04
|
|
288
|
+
|
|
282
289
|
### Changed
|
|
283
290
|
|
|
284
291
|
- Extracted word navigation logic into reusable `moveWordLeft` and `moveWordRight` utility functions for consistent cursor movement across components
|
|
285
292
|
|
|
286
293
|
## [13.6.2] - 2026-03-03
|
|
294
|
+
|
|
287
295
|
### Fixed
|
|
288
296
|
|
|
289
297
|
- Fixed cursor positioning when content shrinks to empty without clearOnShrink enabled
|
|
@@ -293,6 +301,7 @@
|
|
|
293
301
|
### Fixed
|
|
294
302
|
|
|
295
303
|
- 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))
|
|
304
|
+
|
|
296
305
|
## [13.5.3] - 2026-03-01
|
|
297
306
|
|
|
298
307
|
### Fixed
|
|
@@ -302,6 +311,7 @@
|
|
|
302
311
|
- Fixed cursor positioning instability when appending content under external cursor relocation by using absolute screen addressing instead of relative cursor movement
|
|
303
312
|
|
|
304
313
|
## [13.5.2] - 2026-03-01
|
|
314
|
+
|
|
305
315
|
### Breaking Changes
|
|
306
316
|
|
|
307
317
|
- Removed `getMermaidImage` callback from MarkdownTheme; replaced with `getMermaidAscii` that accepts ASCII string instead of image data
|
|
@@ -312,6 +322,7 @@
|
|
|
312
322
|
- Mermaid diagrams now render as ASCII text instead of terminal graphics protocol images
|
|
313
323
|
|
|
314
324
|
## [13.5.1] - 2026-03-01
|
|
325
|
+
|
|
315
326
|
### Fixed
|
|
316
327
|
|
|
317
328
|
- Fixed viewport shift handling to prevent stale content when mixed updates remap screen rows
|
|
@@ -339,6 +350,7 @@
|
|
|
339
350
|
|
|
340
351
|
- 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
352
|
- Fixed scroll overshoot on `stop()` when content fills the viewport by clamping target row movement to valid screen rows.
|
|
353
|
+
|
|
342
354
|
## [13.4.0] - 2026-03-01
|
|
343
355
|
|
|
344
356
|
### Added
|
|
@@ -360,6 +372,7 @@
|
|
|
360
372
|
- 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
373
|
|
|
362
374
|
## [13.3.8] - 2026-02-28
|
|
375
|
+
|
|
363
376
|
### Breaking Changes
|
|
364
377
|
|
|
365
378
|
- Changed mermaid hash type from string to bigint in `getMermaidImage` callback and `extractMermaidBlocks` return type
|
|
@@ -381,6 +394,7 @@
|
|
|
381
394
|
- Fixed stale viewport rows appearing when terminal height increases by triggering full re-render on height changes
|
|
382
395
|
|
|
383
396
|
## [12.18.0] - 2026-02-21
|
|
397
|
+
|
|
384
398
|
### Fixed
|
|
385
399
|
|
|
386
400
|
- Fixed viewport synchronization issue by clearing scrollback when terminal state becomes desynced during full re-renders
|
|
@@ -409,18 +423,21 @@
|
|
|
409
423
|
- Fixed incremental stale-row clearing to use erase-below semantics in synchronized output, reducing leftover-line artifacts after shrink operations.
|
|
410
424
|
|
|
411
425
|
## [12.9.0] - 2026-02-17
|
|
426
|
+
|
|
412
427
|
### Added
|
|
413
428
|
|
|
414
429
|
- Exported `getTerminalId()` function to get a stable identifier for the current terminal, with support for TTY device paths and terminal multiplexers
|
|
415
430
|
- Exported `getTtyPath()` function to resolve the TTY device path for stdin via POSIX `ttyname(3)`
|
|
416
431
|
|
|
417
432
|
## [12.5.0] - 2026-02-15
|
|
433
|
+
|
|
418
434
|
### Added
|
|
419
435
|
|
|
420
436
|
- Added `cursorOverride` and `cursorOverrideWidth` properties to customize the end-of-text cursor glyph with ANSI-styled strings
|
|
421
437
|
- Added `getUseTerminalCursor()` method to query the terminal cursor mode setting
|
|
422
438
|
|
|
423
439
|
## [11.10.0] - 2026-02-10
|
|
440
|
+
|
|
424
441
|
### Added
|
|
425
442
|
|
|
426
443
|
- Added `hint` property to autocomplete items to display dim ghost text after cursor when item is selected
|
|
@@ -433,6 +450,7 @@
|
|
|
433
450
|
- Updated editor to render inline hint text as dim ghost text after cursor when autocomplete suggestions are active or provider supplies hints
|
|
434
451
|
|
|
435
452
|
## [11.8.0] - 2026-02-10
|
|
453
|
+
|
|
436
454
|
### Added
|
|
437
455
|
|
|
438
456
|
- Added Alt+Y keybinding to cycle through kill ring entries (yank-pop)
|
|
@@ -449,6 +467,7 @@
|
|
|
449
467
|
- Changed undo coalescing in Input component to group consecutive word typing into single undo units
|
|
450
468
|
|
|
451
469
|
## [11.4.1] - 2026-02-06
|
|
470
|
+
|
|
452
471
|
### Fixed
|
|
453
472
|
|
|
454
473
|
- Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of blank lines from being output
|
|
@@ -541,6 +560,7 @@
|
|
|
541
560
|
- Fixed handling of private use Unicode codepoints (U+E000 to U+F8FF) in Kitty key decoding to prevent invalid character interpretation
|
|
542
561
|
|
|
543
562
|
## [9.7.0] - 2026-02-01
|
|
563
|
+
|
|
544
564
|
### Breaking Changes
|
|
545
565
|
|
|
546
566
|
- Removed `Key` helper object from public API; use string literals like `"ctrl+c"` instead of `Key.ctrl("c")`
|
|
@@ -552,6 +572,7 @@
|
|
|
552
572
|
- Simplified `isKeyRelease()` and `isKeyRepeat()` to use regex pattern matching instead of string inclusion checks
|
|
553
573
|
|
|
554
574
|
## [9.6.2] - 2026-02-01
|
|
575
|
+
|
|
555
576
|
### Changed
|
|
556
577
|
|
|
557
578
|
- Renamed `EllipsisKind` enum to `Ellipsis` for clearer API naming
|
|
@@ -565,6 +586,7 @@
|
|
|
565
586
|
- Removed `extractAnsiCode` function from public API
|
|
566
587
|
|
|
567
588
|
## [9.6.1] - 2026-02-01
|
|
589
|
+
|
|
568
590
|
### Changed
|
|
569
591
|
|
|
570
592
|
- Improved performance of key ID parsing with optimized cache lookup strategy
|
|
@@ -575,12 +597,14 @@
|
|
|
575
597
|
- Removed `visibleWidth` benchmark file in favor of Kitty sequence benchmarking
|
|
576
598
|
|
|
577
599
|
## [9.5.0] - 2026-02-01
|
|
600
|
+
|
|
578
601
|
### Changed
|
|
579
602
|
|
|
580
603
|
- Improved fuzzy file search performance by using native implementation instead of spawning external process
|
|
581
604
|
- Replaced external `fd` binary with native fuzzy path search for `@`-prefixed autocomplete
|
|
582
605
|
|
|
583
606
|
## [9.4.0] - 2026-01-31
|
|
607
|
+
|
|
584
608
|
### Added
|
|
585
609
|
|
|
586
610
|
- Exported `padding` utility function for creating space-padded strings efficiently
|
|
@@ -592,59 +616,74 @@
|
|
|
592
616
|
## [9.2.2] - 2026-01-31
|
|
593
617
|
|
|
594
618
|
### Added
|
|
619
|
+
|
|
595
620
|
- Added setAutocompleteMaxVisible() configuration (3-20 items)
|
|
596
621
|
- Added image detection to terminal capabilities (containsImage method)
|
|
597
622
|
- Added stdin monitoring to detect stalled input events and log warnings
|
|
598
623
|
|
|
599
624
|
### Changed
|
|
625
|
+
|
|
600
626
|
- Improved blockquote rendering with text wrapping in Markdown component
|
|
601
627
|
- Restructured terminal capabilities from interface-based to class-based model
|
|
602
628
|
- Improved table column width calculation with word-aware wrapping
|
|
603
629
|
- Refactored text utilities to use native WASM implementations for strings >256 chars with JS fast path
|
|
604
630
|
|
|
605
631
|
### Fixed
|
|
632
|
+
|
|
606
633
|
- Simplified terminal write error handling to mark terminal as dead on any write failure
|
|
607
634
|
- Fixed multi-line strings in renderOutputBlock causing width overflow
|
|
608
635
|
- Fixed slash command autocomplete applying stale completion when typing quickly
|
|
609
636
|
|
|
610
637
|
### Removed
|
|
638
|
+
|
|
611
639
|
- Removed TUI layout engine exports from public API (BoxNode, ColumnNode, LayoutNode, etc.)
|
|
612
640
|
|
|
613
641
|
## [8.12.7] - 2026-01-29
|
|
614
642
|
|
|
615
643
|
### Fixed
|
|
644
|
+
|
|
616
645
|
- Fixed slash command autocomplete applying stale completion when typing quickly
|
|
617
646
|
|
|
618
647
|
## [8.4.1] - 2026-01-25
|
|
619
648
|
|
|
620
649
|
### Added
|
|
650
|
+
|
|
621
651
|
- Added fuzzy match function for autocomplete suggestions
|
|
652
|
+
|
|
622
653
|
## [8.4.0] - 2026-01-25
|
|
623
654
|
|
|
624
655
|
### Changed
|
|
656
|
+
|
|
625
657
|
- Added Ctrl+Backspace as a delete-word-backward keybinding and improved modified backspace matching
|
|
626
658
|
|
|
627
659
|
### Fixed
|
|
660
|
+
|
|
628
661
|
- Terminal gracefully handles write failures by marking dead instead of exiting the process
|
|
629
662
|
- Reserved cursor space for zero padding and corrected end-of-line cursor rendering to prevent wrap glitches
|
|
630
663
|
- Corrected editor end-of-line cursor rendering assertion to use includes() instead of endsWith()
|
|
664
|
+
|
|
631
665
|
## [8.2.0] - 2026-01-24
|
|
632
666
|
|
|
633
667
|
### Added
|
|
668
|
+
|
|
634
669
|
- Added mermaid diagram rendering engine (renderMermaidToPng) with mmdc CLI integration
|
|
635
670
|
- Added terminal graphics encoding (iTerm2/Kitty) for mermaid diagrams with automatic width scaling
|
|
636
671
|
- Added mermaid block extraction and deduplication utilities (extractMermaidBlocks)
|
|
637
672
|
|
|
638
673
|
### Changed
|
|
674
|
+
|
|
639
675
|
- Updated TypeScript configuration for better publish-time configuration handling with tsconfig.publish.json
|
|
640
676
|
- Migrated file system operations from synchronous to asynchronous APIs in autocomplete provider for non-blocking I/O
|
|
641
677
|
- Migrated node module imports from named to namespace imports across all packages for consistency with project guidelines
|
|
642
678
|
|
|
643
679
|
### Fixed
|
|
680
|
+
|
|
644
681
|
- Fixed crash when terminal becomes unavailable (EIO errors) by exiting gracefully instead of throwing
|
|
645
682
|
- Fixed potential errors during emergency terminal restore when terminal is already dead
|
|
646
683
|
- Fixed autocomplete race condition by tracking request ID to prevent stale suggestion results
|
|
684
|
+
|
|
647
685
|
## [6.8.3] - 2026-01-21
|
|
686
|
+
|
|
648
687
|
### Added
|
|
649
688
|
|
|
650
689
|
- Added undo support in the editor via `Ctrl+-`
|
|
@@ -700,6 +739,7 @@
|
|
|
700
739
|
- Fixed Alt+letter key combinations for better recognition
|
|
701
740
|
|
|
702
741
|
## [5.3.1] - 2026-01-15
|
|
742
|
+
|
|
703
743
|
### Fixed
|
|
704
744
|
|
|
705
745
|
- Fixed rendering issues on Windows by preventing re-entrant renders
|
|
@@ -729,27 +769,32 @@
|
|
|
729
769
|
## [4.7.0] - 2026-01-12
|
|
730
770
|
|
|
731
771
|
### Fixed
|
|
772
|
+
|
|
732
773
|
- Remove trailing space padding from Text, Markdown, and TruncatedText components when no background color is set (fixes copied text including unwanted whitespace)
|
|
733
774
|
|
|
734
775
|
## [4.6.0] - 2026-01-12
|
|
735
776
|
|
|
736
777
|
### Added
|
|
778
|
+
|
|
737
779
|
- Add fuzzy matching module (`fuzzyMatch`, `fuzzyFilter`) for command autocomplete
|
|
738
780
|
- Add `getExpandedText()` to editor for expanding paste markers
|
|
739
781
|
- Add backslash+enter newline fallback for terminals without Kitty protocol
|
|
740
782
|
|
|
741
783
|
### Fixed
|
|
784
|
+
|
|
742
785
|
- Remove Kitty protocol query timeout that caused shift+enter delays
|
|
743
786
|
- Add bracketed paste check to prevent false key release/repeat detection
|
|
744
787
|
- Rendering optimizations: only re-render changed lines
|
|
745
788
|
- Refactor input component to use keybindings manager
|
|
746
789
|
|
|
747
790
|
## [4.4.4] - 2026-01-11
|
|
791
|
+
|
|
748
792
|
### Fixed
|
|
749
793
|
|
|
750
794
|
- Fixed Ctrl+Enter sequences to insert new lines in the editor
|
|
751
795
|
|
|
752
796
|
## [4.2.1] - 2026-01-11
|
|
797
|
+
|
|
753
798
|
### Changed
|
|
754
799
|
|
|
755
800
|
- 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 +805,13 @@
|
|
|
760
805
|
- Fixed `fd` tool detection to automatically find `fd` or `fdfind` in PATH when not explicitly configured
|
|
761
806
|
|
|
762
807
|
## [4.1.0] - 2026-01-10
|
|
808
|
+
|
|
763
809
|
### Added
|
|
764
810
|
|
|
765
811
|
- Added persistent prompt history storage support via `setHistoryStorage()` method, allowing history to be saved and restored across sessions
|
|
766
812
|
|
|
767
813
|
## [4.0.0] - 2026-01-10
|
|
814
|
+
|
|
768
815
|
### Added
|
|
769
816
|
|
|
770
817
|
- `EditorComponent` interface for custom editor implementations
|
|
@@ -795,6 +842,7 @@
|
|
|
795
842
|
- Fixed text wrapping allowing long whitespace tokens to exceed line width
|
|
796
843
|
|
|
797
844
|
## [3.20.0] - 2026-01-06
|
|
845
|
+
|
|
798
846
|
### Added
|
|
799
847
|
|
|
800
848
|
- Added `isCapsLock` helper function for detecting Caps Lock key press via Kitty protocol
|
|
@@ -826,6 +874,7 @@
|
|
|
826
874
|
- Added support for custom spinner frames in the Loader component
|
|
827
875
|
|
|
828
876
|
## [3.9.1337] - 2026-01-04
|
|
877
|
+
|
|
829
878
|
### Added
|
|
830
879
|
|
|
831
880
|
- Added `setTopBorder()` method to Editor component for displaying custom status content in the top border
|
|
@@ -838,6 +887,7 @@
|
|
|
838
887
|
- Changed cursor style from block to thin blinking bar (▏) at end of line
|
|
839
888
|
|
|
840
889
|
## [1.500.0] - 2026-01-03
|
|
890
|
+
|
|
841
891
|
### Added
|
|
842
892
|
|
|
843
893
|
- Added `getText()` method to Text component for retrieving current text content
|
|
@@ -902,4 +952,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
|
|
|
902
952
|
|
|
903
953
|
### Fixed
|
|
904
954
|
|
|
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))
|
|
955
|
+
- **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/dist/types/terminal.d.ts
CHANGED
|
@@ -56,6 +56,28 @@ export interface Terminal {
|
|
|
56
56
|
export declare function shouldTrustNativeViewportProbe(env?: {
|
|
57
57
|
WT_SESSION?: string | undefined;
|
|
58
58
|
}, platform?: NodeJS.Platform): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Whether eager live-frame native scrollback rebuilds are unsafe for the
|
|
61
|
+
* current POSIX terminal when its viewport position is unobservable.
|
|
62
|
+
*
|
|
63
|
+
* A TUI history rebuild emits xterm ED3 (`CSI 3 J`, erase saved lines). On the
|
|
64
|
+
* terminals below, ED3 can disturb a reader parked in native scrollback during
|
|
65
|
+
* streaming: kitty/ghostty/alacritty clamp the scroll offset back to the active
|
|
66
|
+
* tail when saved lines are erased, and WezTerm is the reported POSIX host for
|
|
67
|
+
* #1682. Defer only the eager streaming opt-in on these hosts; direct
|
|
68
|
+
* user-input renders and explicit checkpoint rebuilds still pass their own
|
|
69
|
+
* `allowUnknownViewportMutation` / `allowUnknownViewport` flags.
|
|
70
|
+
*
|
|
71
|
+
* Pure helper for unit testing; the runtime call site reads `$env` /
|
|
72
|
+
* `process.platform`. See #1682.
|
|
73
|
+
*/
|
|
74
|
+
export declare function terminalHasEagerEraseScrollbackRisk(env?: {
|
|
75
|
+
WEZTERM_PANE?: string | undefined;
|
|
76
|
+
KITTY_WINDOW_ID?: string | undefined;
|
|
77
|
+
GHOSTTY_RESOURCES_DIR?: string | undefined;
|
|
78
|
+
ALACRITTY_WINDOW_ID?: string | undefined;
|
|
79
|
+
TERM_PROGRAM?: string | undefined;
|
|
80
|
+
}, platform?: NodeJS.Platform): boolean;
|
|
59
81
|
/**
|
|
60
82
|
* Real terminal using process.stdin/stdout
|
|
61
83
|
*/
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Terminal } from "./terminal";
|
|
2
2
|
import { visibleWidth } from "./utils";
|
|
3
3
|
type InputListenerResult = {
|
|
4
4
|
consume?: boolean;
|
|
@@ -171,9 +171,11 @@ 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
|
|
175
|
-
*
|
|
176
|
-
*
|
|
174
|
+
* re-laying-out rows that have already scrolled into history. A terminal that
|
|
175
|
+
* can report a *known*-scrolled viewport (Windows) still defers; only the
|
|
176
|
+
* unknown case is forced to rebuild. POSIX hosts known to disturb scrolled
|
|
177
|
+
* readers on xterm ED3 (`CSI 3 J`, erase saved lines) also defer the eager
|
|
178
|
+
* opt-in; checkpoint and direct user-input rebuilds are unaffected.
|
|
177
179
|
*/
|
|
178
180
|
setEagerNativeScrollbackRebuild(enabled: boolean): void;
|
|
179
181
|
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.
|
|
4
|
+
"version": "15.8.0",
|
|
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.
|
|
41
|
-
"@oh-my-pi/pi-utils": "15.
|
|
40
|
+
"@oh-my-pi/pi-natives": "15.8.0",
|
|
41
|
+
"@oh-my-pi/pi-utils": "15.8.0",
|
|
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 ☃ 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,
|
|
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, #
|
|
157
|
-
*
|
|
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 !==
|
|
164
|
-
if (strict && n
|
|
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
|
|
package/src/terminal.ts
CHANGED
|
@@ -134,6 +134,39 @@ export function shouldTrustNativeViewportProbe(
|
|
|
134
134
|
return true;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Whether eager live-frame native scrollback rebuilds are unsafe for the
|
|
139
|
+
* current POSIX terminal when its viewport position is unobservable.
|
|
140
|
+
*
|
|
141
|
+
* A TUI history rebuild emits xterm ED3 (`CSI 3 J`, erase saved lines). On the
|
|
142
|
+
* terminals below, ED3 can disturb a reader parked in native scrollback during
|
|
143
|
+
* streaming: kitty/ghostty/alacritty clamp the scroll offset back to the active
|
|
144
|
+
* tail when saved lines are erased, and WezTerm is the reported POSIX host for
|
|
145
|
+
* #1682. Defer only the eager streaming opt-in on these hosts; direct
|
|
146
|
+
* user-input renders and explicit checkpoint rebuilds still pass their own
|
|
147
|
+
* `allowUnknownViewportMutation` / `allowUnknownViewport` flags.
|
|
148
|
+
*
|
|
149
|
+
* Pure helper for unit testing; the runtime call site reads `$env` /
|
|
150
|
+
* `process.platform`. See #1682.
|
|
151
|
+
*/
|
|
152
|
+
export function terminalHasEagerEraseScrollbackRisk(
|
|
153
|
+
env: {
|
|
154
|
+
WEZTERM_PANE?: string | undefined;
|
|
155
|
+
KITTY_WINDOW_ID?: string | undefined;
|
|
156
|
+
GHOSTTY_RESOURCES_DIR?: string | undefined;
|
|
157
|
+
ALACRITTY_WINDOW_ID?: string | undefined;
|
|
158
|
+
TERM_PROGRAM?: string | undefined;
|
|
159
|
+
} = $env,
|
|
160
|
+
platform: NodeJS.Platform = process.platform,
|
|
161
|
+
): boolean {
|
|
162
|
+
if (platform === "win32") return false;
|
|
163
|
+
if (env.WEZTERM_PANE || env.KITTY_WINDOW_ID || env.GHOSTTY_RESOURCES_DIR || env.ALACRITTY_WINDOW_ID) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
const termProgram = env.TERM_PROGRAM?.toLowerCase();
|
|
167
|
+
return termProgram === "ghostty";
|
|
168
|
+
}
|
|
169
|
+
|
|
137
170
|
/**
|
|
138
171
|
* Real terminal using process.stdin/stdout
|
|
139
172
|
*/
|
package/src/tui.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as path from "node:path";
|
|
|
6
6
|
import { performance } from "node:perf_hooks";
|
|
7
7
|
import { $flag, getDebugLogPath } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import { isKeyRelease, matchesKey } from "./keys";
|
|
9
|
-
import type
|
|
9
|
+
import { type Terminal, terminalHasEagerEraseScrollbackRisk } from "./terminal";
|
|
10
10
|
import { ImageProtocol, setCellDimensions, setTerminalImageProtocol, TERMINAL } from "./terminal-capabilities";
|
|
11
11
|
import {
|
|
12
12
|
Ellipsis,
|
|
@@ -386,9 +386,11 @@ export class TUI extends Container {
|
|
|
386
386
|
* non-destructive repaint. This trades the anti-yank guarantee for a clean,
|
|
387
387
|
* duplicate-free history and is meant for windows where output above the fold
|
|
388
388
|
* is actively re-rendering — e.g. a tool whose result is still streaming and
|
|
389
|
-
* re-laying-out rows that have already scrolled into history. A
|
|
390
|
-
*
|
|
391
|
-
*
|
|
389
|
+
* re-laying-out rows that have already scrolled into history. A terminal that
|
|
390
|
+
* can report a *known*-scrolled viewport (Windows) still defers; only the
|
|
391
|
+
* unknown case is forced to rebuild. POSIX hosts known to disturb scrolled
|
|
392
|
+
* readers on xterm ED3 (`CSI 3 J`, erase saved lines) also defer the eager
|
|
393
|
+
* opt-in; checkpoint and direct user-input rebuilds are unaffected.
|
|
392
394
|
*/
|
|
393
395
|
setEagerNativeScrollbackRebuild(enabled: boolean): void {
|
|
394
396
|
this.#eagerNativeScrollbackRebuild = enabled;
|
|
@@ -664,16 +666,23 @@ export class TUI extends Container {
|
|
|
664
666
|
clearTimeout(this.#renderTimer);
|
|
665
667
|
this.#renderTimer = undefined;
|
|
666
668
|
}
|
|
667
|
-
//
|
|
669
|
+
// Place the parent shell on the first line after the rendered content. When
|
|
670
|
+
// that line is still inside the viewport, moving there and writing `\r` is
|
|
671
|
+
// enough; emitting `\r\n` would create an extra blank row. If the content
|
|
672
|
+
// already reaches the viewport bottom, scroll exactly once so the prompt
|
|
673
|
+
// lands directly below the last visible TUI row.
|
|
668
674
|
if (this.#previousLines.length > 0) {
|
|
669
|
-
const targetRow = this.#previousLines.length;
|
|
670
|
-
const
|
|
675
|
+
const targetRow = this.#previousLines.length;
|
|
676
|
+
const viewportBottom = this.#viewportTopRow + this.terminal.rows - 1;
|
|
677
|
+
const clampedCursorRow = Math.max(this.#viewportTopRow, Math.min(this.#hardwareCursorRow, viewportBottom));
|
|
678
|
+
const moveTargetRow = Math.min(targetRow, viewportBottom);
|
|
679
|
+
const lineDiff = moveTargetRow - clampedCursorRow;
|
|
671
680
|
if (lineDiff > 0) {
|
|
672
681
|
this.terminal.write(`\x1b[${lineDiff}B`);
|
|
673
682
|
} else if (lineDiff < 0) {
|
|
674
683
|
this.terminal.write(`\x1b[${-lineDiff}A`);
|
|
675
684
|
}
|
|
676
|
-
this.terminal.write("\r\n");
|
|
685
|
+
this.terminal.write(targetRow <= viewportBottom ? "\r" : "\r\n");
|
|
677
686
|
}
|
|
678
687
|
|
|
679
688
|
this.terminal.showCursor();
|
|
@@ -1180,8 +1189,8 @@ export class TUI extends Container {
|
|
|
1180
1189
|
const prevHardwareCursorRow = this.#hardwareCursorRow;
|
|
1181
1190
|
const widthChanged = this.#previousWidth > 0 && this.#previousWidth !== width;
|
|
1182
1191
|
const heightChanged = this.#previousHeight > 0 && this.#previousHeight !== height;
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1192
|
+
const eagerRebuildAllowed = this.#eagerNativeScrollbackRebuild && !terminalHasEagerEraseScrollbackRisk();
|
|
1193
|
+
const allowUnknownViewportMutation = this.#allowUnknownViewportMutationOnNextRender || eagerRebuildAllowed;
|
|
1185
1194
|
this.#allowUnknownViewportMutationOnNextRender = false;
|
|
1186
1195
|
|
|
1187
1196
|
// 3. Classify intent.
|
|
@@ -1337,8 +1346,8 @@ export class TUI extends Container {
|
|
|
1337
1346
|
}
|
|
1338
1347
|
// POSIX terminals — and Windows Terminal/ConPTY — that cannot report the
|
|
1339
1348
|
// viewport position fall through here (`canRebuildNativeScrollbackLive` is
|
|
1340
|
-
// false). A destructive rebuild emits `\x1b[3J
|
|
1341
|
-
//
|
|
1349
|
+
// false). A destructive rebuild emits `\x1b[3J` (xterm erase saved lines),
|
|
1350
|
+
// which can clear or reposition native scrollback and yank a scrolled-up
|
|
1342
1351
|
// reader (issue #1635), so it is unsafe while the probe is unavailable.
|
|
1343
1352
|
//
|
|
1344
1353
|
// When the shrunk transcript now fits entirely in the viewport there is no
|
|
@@ -1660,8 +1669,8 @@ export class TUI extends Container {
|
|
|
1660
1669
|
/**
|
|
1661
1670
|
* Live-frame counterpart to {@link #canReplayNativeScrollbackAtCheckpoint}.
|
|
1662
1671
|
* Decides whether a destructive native scrollback rebuild
|
|
1663
|
-
* (`historyRebuild`/`overlayRebuild`, which
|
|
1664
|
-
*
|
|
1672
|
+
* (`historyRebuild`/`overlayRebuild`, which clears saved lines and may move
|
|
1673
|
+
* the native viewport) is safe to emit *during ordinary rendering*. POSIX
|
|
1665
1674
|
* terminals cannot report whether the user has scrolled up
|
|
1666
1675
|
* (`isNativeViewportAtBottom()` is `undefined`), so an unknown position is
|
|
1667
1676
|
* treated as unsafe: defer to a non-destructive viewport repaint, mark
|
|
@@ -1669,10 +1678,11 @@ export class TUI extends Container {
|
|
|
1669
1678
|
* ({@link refreshNativeScrollbackIfDirty} on prompt submit) where the
|
|
1670
1679
|
* editor keystroke has already pinned the terminal to the bottom. Without
|
|
1671
1680
|
* this, every offscreen transcript edit while streaming wiped scrollback and
|
|
1672
|
-
* yanked a scrolled-up reader
|
|
1673
|
-
* (autocomplete/IME) opts directly
|
|
1674
|
-
* Unlike the checkpoint predicate
|
|
1675
|
-
* optimism — resize and checkpoint replays
|
|
1681
|
+
* yanked a scrolled-up reader out of their current context.
|
|
1682
|
+
* `allowUnknownViewportMutation` (autocomplete/IME) opts directly
|
|
1683
|
+
* user-driven frames back into the rebuild. Unlike the checkpoint predicate
|
|
1684
|
+
* this carries no `process.platform` optimism — resize and checkpoint replays
|
|
1685
|
+
* keep using that one.
|
|
1676
1686
|
*/
|
|
1677
1687
|
#canRebuildNativeScrollbackLive(
|
|
1678
1688
|
nativeViewportAtBottom: boolean | undefined,
|