@oh-my-pi/pi-tui 15.12.4 → 15.13.1
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 +291 -21
- package/dist/types/components/editor.d.ts +25 -0
- package/dist/types/components/image.d.ts +12 -2
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/loop-watchdog.d.ts +39 -0
- package/dist/types/tui.d.ts +50 -3
- package/package.json +3 -3
- package/src/components/editor.ts +184 -61
- package/src/components/image.ts +32 -3
- package/src/components/select-list.ts +13 -3
- package/src/keybindings.ts +1 -1
- package/src/loop-watchdog.ts +106 -0
- package/src/tui.ts +384 -26
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.13.1] - 2026-06-15
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- 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
|
|
10
|
+
- 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))
|
|
11
|
+
- 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))
|
|
12
|
+
- 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.
|
|
13
|
+
- 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.
|
|
14
|
+
- 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.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- 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.
|
|
19
|
+
- 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)).
|
|
20
|
+
- 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.
|
|
21
|
+
- 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)).
|
|
22
|
+
|
|
23
|
+
## [15.12.6] - 2026-06-14
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- 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
|
|
28
|
+
- 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
|
|
29
|
+
|
|
30
|
+
## [15.12.5] - 2026-06-13
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Added `ViewportTailProvider` to let child components provide their visible tail rows during fast-path non-multiplexer resize rendering
|
|
35
|
+
- Added `TUI.resizeViewportPaints` and `TUI.resizeViewportActive` getters to expose deferred resize viewport repaint diagnostics
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- 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
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- 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
|
|
44
|
+
|
|
5
45
|
## [15.12.4] - 2026-06-13
|
|
6
46
|
|
|
7
47
|
### Added
|
|
@@ -147,6 +187,27 @@
|
|
|
147
187
|
- 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.
|
|
148
188
|
- 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).
|
|
149
189
|
|
|
190
|
+
## [15.10.10] - 2026-06-09
|
|
191
|
+
|
|
192
|
+
### Fixed
|
|
193
|
+
|
|
194
|
+
- 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.
|
|
195
|
+
- 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.
|
|
196
|
+
- 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.
|
|
197
|
+
|
|
198
|
+
### Changed
|
|
199
|
+
|
|
200
|
+
- 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.
|
|
201
|
+
- 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).
|
|
202
|
+
- 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.
|
|
203
|
+
- 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.
|
|
204
|
+
- 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).
|
|
205
|
+
|
|
206
|
+
### Removed
|
|
207
|
+
|
|
208
|
+
- 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.
|
|
209
|
+
- 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).
|
|
210
|
+
|
|
150
211
|
## [15.10.9] - 2026-06-09
|
|
151
212
|
|
|
152
213
|
### Added
|
|
@@ -246,7 +307,6 @@
|
|
|
246
307
|
### Fixed
|
|
247
308
|
|
|
248
309
|
- Fixed `Loader` text updates to skip identical messages and preserve the rendered `Text` cache instead of invalidating it every timer tick.
|
|
249
|
-
|
|
250
310
|
- Fixed fullscreen overlay alt-frame rendering to reuse the current line-preparation path instead of calling removed fitting helpers.
|
|
251
311
|
- Reduced TUI render-path line fitting by deferring overlay base-frame fitting until an overlay rebuild and by reusing already-fitted lines in emitters.
|
|
252
312
|
- Reduced live-region pinned repaint output by diffing unchanged viewport rows when no sealed rows are being committed to native scrollback.
|
|
@@ -385,7 +445,6 @@
|
|
|
385
445
|
- Fixed the DECCARA background-fill optimizer rejecting or repainting the wrong cells when a trailing fill crossed from default-background spaces into colored spaces.
|
|
386
446
|
- Fixed DEC private-mode reports with DECRPM status 3/4 being treated as unsupported, so permanent 2026/2048 reports stay recognized.
|
|
387
447
|
- Fixed OSC 66 text-sizing width and slicing edge cases, including ZWJ emoji payloads and partial slices through scaled spans.
|
|
388
|
-
|
|
389
448
|
- Fixed focused `Input` components following `TUI#setShowHardwareCursor`, so single-line prompts render either the terminal cursor or software cursor consistently with the editor.
|
|
390
449
|
- 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.
|
|
391
450
|
- Fixed native scrollback desynchronization after terminal width or height changes reflowed overflowing content while the viewport was not at the bottom
|
|
@@ -521,7 +580,6 @@
|
|
|
521
580
|
### Fixed
|
|
522
581
|
|
|
523
582
|
- 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))
|
|
524
|
-
- 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))
|
|
525
583
|
|
|
526
584
|
## [15.2.3] - 2026-05-22
|
|
527
585
|
|
|
@@ -556,19 +614,6 @@
|
|
|
556
614
|
### Breaking Changes
|
|
557
615
|
|
|
558
616
|
- Increased the minimum required Bun version for the TUI package from >=1.3.7 to >=1.3.14
|
|
559
|
-
- Fixed `TerminalInfo.sendNotification` not delivering desktop notifications on macOS. macOS requires per-app notification permission, which terminal emulators (kitty, ghostty, alacritty, …) almost never have, so OSC 9/99 sequences were silently dropped at the OS layer. `sendNotification` now shells out to `alerter` or `terminal-notifier` when either is on `$PATH` (both register their own LSApplication and ship a "Terminal" / `>_` icon). When neither is installed the dispatch is a deliberate no-op + a single `logger.warn` line on the first miss (subsequent dispatches stay silent) so the user can spot the missing binary in `~/.omp/logs/omp.YYYY-MM-DD.log` and `brew install alerter`. Linux/Windows still go through the OSC/Bell path.
|
|
560
|
-
- Fixed `TerminalInfo.formatNotification` losing OSC 9/99 desktop notifications when running inside tmux. The OSC sequence is now wrapped in tmux's DCS passthrough envelope (`\ePtmux;…\e\\` with embedded ESC bytes doubled) when `TMUX` is set, so notifications reach the parent terminal. `set -g allow-passthrough on` is still required on the tmux side for the wrapped sequence to be forwarded. Bell-only terminals are unchanged.
|
|
561
|
-
- Fixed alerter desktop notifications staying on screen indefinitely. `scripts/mac-alerter.sh` previously passed `--timeout 30` (which makes alerter call `removeDeliveredNotification` after 30 s, also purging the Notification Center entry) and forced Alert-style via `--actions "Open"` (persistent until user click). It now ships Banner-style argv (no `--actions`, no `--timeout`): macOS auto-dismisses the toast after ~10 s and archives the entry to Notification Center for later review. Click-to-focus is preserved through `@CONTENTCLICKED` body clicks. NC archival also requires "Show in Notification Center" enabled for Terminal under macOS System Settings → Notifications.
|
|
562
|
-
- Fixed `composeNotificationSubtitle` showing a stale tmux `pane_title` (typically `π: kitty & tmux` or the cwd prefix written before auto-naming runs) instead of the live OMP session name. The OMP-supplied `fallback` is now consulted first for the pane component; the cached tmux pane title is only used when no session name is available. Window name handling is unchanged.
|
|
563
|
-
- Fixed `sendDesktopNotification` always routing through `alerter` / `terminal-notifier` on darwin, even for terminals (ghostty / iTerm2 / wezterm) that surface OSC 9 / OSC 99 as native notifications through their own bundle. The dispatch now prefers the OSC path on darwin when the terminal advertises native macOS notification capability; the fallback only kicks in for kitty / alacritty / vscode / unknown shells whose host app isn't a notification-capable bundle. This unblocks the user-controlled per-app notification settings flow for ghostty / iTerm2 / wezterm — toast style, NC archival, and click-to-focus all attach to the terminal app's own System Settings entry rather than to `com.apple.Terminal` (which `alerter` would post under).
|
|
564
|
-
- Fixed Korean IME composition leaving a growing horizontal gap between typed jamo and the cursor inside the OMP prompt under tmux + ghostty (and other macOS terminals). `Bun.stringWidth` and the underlying UAX#11 East Asian Width tables classify Hangul Compatibility Jamo (U+3131..U+318E — ㄱ ㄴ ㄷ ㄹ ㅁ ㅂ ㅅ ㅇ ㅈ ㅊ ㅋ ㅌ ㅍ ㅎ + filler) as Wide (2 cells), but every macOS terminal we ship to (Ghostty / Terminal.app / iTerm2) actually renders them as a single cell in monospace fonts. `#extractCursorPosition` was computing `col = visibleWidth(beforeMarker)` and feeding the doubled value to `\x1b[(col+1)G`, placing the hardware cursor (and therefore the IME candidate window) `N_jamo` cells past the visible glyph — exactly the gap the user saw growing as they typed. `visibleWidthRaw` now subtracts 1 cell for each Compatibility Jamo character, returning the column count macOS terminals actually use. Hangul Syllables (U+AC00..U+D7A3, e.g. `안`) stay at 2 cells in both Bun and the terminal — unaffected. Other CJK widths (Chinese / Japanese / Halfwidth Hangul) are unchanged. NOTE: the Rust `pi-natives` width tables (used by `sliceWithWidth` / `truncateToWidth` / `wrapTextWithAnsi`) also count Compatibility Jamo as 2 cells; truncation and word-wrap on jamo-heavy lines will still be slightly aggressive. The defect is invisible in normal use because the AI composes Korean as syllables, not jamo, and users type syllables once IME composition completes. A follow-up will reconcile the Rust side.
|
|
565
|
-
- Fixed a brief black-flash flicker in the TUI when streaming long markdown responses inside tmux (especially noticeable in ghostty with multiple panes open). Root cause: when a markdown fence line above the viewport changed between two streaming tokens (e.g. `` ``` `` → `` ```python ``), `#doRender()` would take the `firstChanged < prevViewportTop` branch and emit `\x1b[2J\x1b[H` (full screen clear + cursor home) wrapped in BSU. The BSU envelope can split across PTY reads, leaving tmux briefly displaying a blank pane before the rest of the buffer arrives — multiplied across panes during repaint. The viewport-above branch now calls a new `viewportRefresh()` helper that does cursor-home + per-line `\x1b[2K` + line content (no `\x1b[2J`), so the visible viewport content is repainted without ever clearing the screen. Scrollback above the viewport may briefly show stale rendering, but only of the SAME lines that just changed — invisible during streaming when the user isn't scrolled up. Other full-redraw paths (resize, first render, etc.) keep the hard `fullRender(true)` behavior unchanged.
|
|
566
|
-
|
|
567
|
-
### Tests
|
|
568
|
-
|
|
569
|
-
- Added `test/no-2k-anywhere.test.ts` — lint guard that scans `packages/tui/src/` for `\x1b[2K` string literals outside comments. The earlier streaming-flicker fix re-introduced the BSU-split flash bug by moving `\x1b[2K`-before-content from `fullRender` to `viewportRefresh` (same anti-pattern in a new location). This test catches that class of regression at CI time so future changes can't silently revive it.
|
|
570
|
-
- Added `test/render-emit-snapshot.test.ts` — four scenario-based byte-snapshot guards (single-line mutation, streaming append, above-viewport mutation triggering `viewportRefresh`, trailing-line clear on shrink). Asserts structural invariants on the EMITTED BYTES from `terminal.write(…)`: no `\x1b[2K`, no `\x1b[2J`, the new content appears, the BSU close `\x1b[?2026l` is present. Catches render-path changes that achieve the right final viewport state via a transient blank frame (which is exactly how the typing-flicker bug slipped past `render-regressions.test.ts`).
|
|
571
|
-
- Added `test/ime-jamo-cursor.test.ts` — six cases asserting the Input component's hardware cursor marker column does not grow at 2× per typed Korean compatibility jamo. Before commit `79e3170c6` typing 14 jamo produced a 14-cell gap between the visible text and the IME candidate window; the test caps the cursor column at `PROMPT_WIDTH + N_jamo` and asserts the per-keystroke delta is at most 1. NOTE: the Rust `pi-natives` `sliceWithWidth` still treats jamo as 2 cells (binary package, follow-up); the test guard accepts a small residual offset but flags the doubling regression.
|
|
572
617
|
|
|
573
618
|
## [14.9.8] - 2026-05-12
|
|
574
619
|
|
|
@@ -601,7 +646,6 @@
|
|
|
601
646
|
- 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`)
|
|
602
647
|
- 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`)
|
|
603
648
|
- Fixed Markdown strikethrough requiring strict `~~text~~` delimiters with non-whitespace boundaries; single tildes no longer render strikethrough (ports pi-mono `db5274b4`)
|
|
604
|
-
|
|
605
649
|
- Allowed `SlashCommand.getArgumentCompletions` to return asynchronous results by accepting Promise-based completions
|
|
606
650
|
- Added `argumentHint` support to slash command definitions and displayed it in command suggestion descriptions
|
|
607
651
|
- Added support for xterm `modifyOtherKeys` printable key sequences by decoding `CSI 27;mod;key~` into text input
|
|
@@ -636,10 +680,6 @@
|
|
|
636
680
|
|
|
637
681
|
- Changed truncation debug logging to run only when `debugRedraw` is enabled
|
|
638
682
|
|
|
639
|
-
### Fixed
|
|
640
|
-
|
|
641
|
-
- Fixed viewport jumping during streaming and session swap by tracking actual content height instead of high-water mark
|
|
642
|
-
|
|
643
683
|
## [14.0.5] - 2026-04-11
|
|
644
684
|
|
|
645
685
|
### Changed
|
|
@@ -1338,6 +1378,236 @@
|
|
|
1338
1378
|
|
|
1339
1379
|
Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mono](https://github.com/badlogic/pi-mono).
|
|
1340
1380
|
|
|
1381
|
+
## [1.5.0] - 2026-01-03
|
|
1382
|
+
|
|
1383
|
+
### Added
|
|
1384
|
+
|
|
1385
|
+
- Added `getText()` method to Text component for retrieving current text content
|
|
1386
|
+
|
|
1387
|
+
## [0.50.0] - 2026-01-26
|
|
1388
|
+
|
|
1389
|
+
### Added
|
|
1390
|
+
|
|
1391
|
+
- Added `fullRedraws` readonly property to TUI class for tracking full screen redraws
|
|
1392
|
+
- Added `PI_TUI_WRITE_LOG` environment variable to capture raw ANSI output for debugging
|
|
1393
|
+
|
|
1394
|
+
### Fixed
|
|
1395
|
+
|
|
1396
|
+
- 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))
|
|
1397
|
+
- Slash command menu now only triggers when the editor input is otherwise empty ([#904](https://github.com/badlogic/pi-mono/issues/904))
|
|
1398
|
+
- 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))
|
|
1399
|
+
- Fixed editor multi-line insertion handling and lastAction tracking ([#945](https://github.com/badlogic/pi-mono/pull/945) by [@Perlence](https://github.com/Perlence))
|
|
1400
|
+
- Fixed editor word wrapping to reserve a cursor column ([#934](https://github.com/badlogic/pi-mono/pull/934) by [@Perlence](https://github.com/Perlence))
|
|
1401
|
+
- 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))
|
|
1402
|
+
- Fixed Kitty image ID allocation and cleanup to prevent image ID collisions between modules
|
|
1403
|
+
|
|
1404
|
+
## [0.49.3] - 2026-01-22
|
|
1405
|
+
|
|
1406
|
+
### Added
|
|
1407
|
+
|
|
1408
|
+
- `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))
|
|
1409
|
+
- Added Alt+Delete as hotkey for delete word forwards ([#878](https://github.com/badlogic/pi-mono/pull/878) by [@Perlence](https://github.com/Perlence))
|
|
1410
|
+
|
|
1411
|
+
### Changed
|
|
1412
|
+
|
|
1413
|
+
- 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))
|
|
1414
|
+
|
|
1415
|
+
### Fixed
|
|
1416
|
+
|
|
1417
|
+
- 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))
|
|
1418
|
+
- Fixed viewport tracking and cursor positioning for overlays and content shrink scenarios
|
|
1419
|
+
- 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))
|
|
1420
|
+
- Directory completions for `@` file attachments no longer add trailing space, allowing continued autocomplete into subdirectories
|
|
1421
|
+
|
|
1422
|
+
## [0.49.1] - 2026-01-18
|
|
1423
|
+
|
|
1424
|
+
### Added
|
|
1425
|
+
|
|
1426
|
+
- 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))
|
|
1427
|
+
- 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))
|
|
1428
|
+
|
|
1429
|
+
## [0.49.0] - 2026-01-17
|
|
1430
|
+
|
|
1431
|
+
### Added
|
|
1432
|
+
|
|
1433
|
+
- 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))
|
|
1434
|
+
- 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))
|
|
1435
|
+
- 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))
|
|
1436
|
+
|
|
1437
|
+
## [0.48.0] - 2026-01-16
|
|
1438
|
+
|
|
1439
|
+
### Added
|
|
1440
|
+
|
|
1441
|
+
- `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))
|
|
1442
|
+
|
|
1443
|
+
### Changed
|
|
1444
|
+
|
|
1445
|
+
- 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).
|
|
1446
|
+
|
|
1447
|
+
### Fixed
|
|
1448
|
+
|
|
1449
|
+
- 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))
|
|
1450
|
+
|
|
1451
|
+
## [0.47.0] - 2026-01-16
|
|
1452
|
+
|
|
1453
|
+
### Breaking Changes
|
|
1454
|
+
|
|
1455
|
+
- `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))
|
|
1456
|
+
|
|
1457
|
+
### Added
|
|
1458
|
+
|
|
1459
|
+
- 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))
|
|
1460
|
+
- `Focusable` interface for components that need hardware cursor positioning. Implement `focused: boolean` and emit `CURSOR_MARKER` in render output when focused.
|
|
1461
|
+
- `CURSOR_MARKER` constant and `isFocusable()` type guard exported from the package
|
|
1462
|
+
- 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))
|
|
1463
|
+
- 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))
|
|
1464
|
+
|
|
1465
|
+
### Fixed
|
|
1466
|
+
|
|
1467
|
+
- 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))
|
|
1468
|
+
- `visibleWidth()` and `extractAnsiCode()` now handle APC escape sequences (`ESC _ ... BEL`), fixing width calculation and string slicing for strings containing cursor markers
|
|
1469
|
+
- 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))
|
|
1470
|
+
|
|
1471
|
+
## [0.46.0] - 2026-01-15
|
|
1472
|
+
|
|
1473
|
+
### Fixed
|
|
1474
|
+
|
|
1475
|
+
- 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))
|
|
1476
|
+
|
|
1477
|
+
## [0.45.6] - 2026-01-13
|
|
1478
|
+
|
|
1479
|
+
### Added
|
|
1480
|
+
|
|
1481
|
+
- `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))
|
|
1482
|
+
- `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))
|
|
1483
|
+
- `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))
|
|
1484
|
+
- New exported types: `OverlayAnchor`, `OverlayHandle`, `OverlayMargin`, `OverlayOptions`, `SizeValue` ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
|
|
1485
|
+
- `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))
|
|
1486
|
+
|
|
1487
|
+
### Fixed
|
|
1488
|
+
|
|
1489
|
+
- 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))
|
|
1490
|
+
|
|
1491
|
+
## [0.44.0] - 2026-01-12
|
|
1492
|
+
|
|
1493
|
+
### Added
|
|
1494
|
+
|
|
1495
|
+
- `SettingsListOptions` with `enableSearch` for fuzzy filtering in `SettingsList` ([#643](https://github.com/badlogic/pi-mono/pull/643) by [@ninlds](https://github.com/ninlds))
|
|
1496
|
+
- `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))
|
|
1497
|
+
|
|
1498
|
+
### Fixed
|
|
1499
|
+
|
|
1500
|
+
- 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))
|
|
1501
|
+
|
|
1502
|
+
## [0.43.0] - 2026-01-11
|
|
1503
|
+
|
|
1504
|
+
### Added
|
|
1505
|
+
|
|
1506
|
+
- `fuzzyFilter()` and `fuzzyMatch()` utilities for fuzzy text matching
|
|
1507
|
+
- Slash command autocomplete now uses fuzzy matching instead of prefix matching
|
|
1508
|
+
|
|
1509
|
+
### Fixed
|
|
1510
|
+
|
|
1511
|
+
- 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))
|
|
1512
|
+
- Reset ANSI styles after each rendered line to prevent style leakage
|
|
1513
|
+
|
|
1514
|
+
## [0.42.5] - 2026-01-11
|
|
1515
|
+
|
|
1516
|
+
### Fixed
|
|
1517
|
+
|
|
1518
|
+
- Reduced flicker by only re-rendering changed lines ([#617](https://github.com/badlogic/pi-mono/pull/617) by [@ogulcancelik](https://github.com/ogulcancelik))
|
|
1519
|
+
- Cursor position tracking when content shrinks with unchanged remaining lines
|
|
1520
|
+
- TUI renders with wrong dimensions after suspend/resume if terminal was resized while suspended ([#599](https://github.com/badlogic/pi-mono/issues/599))
|
|
1521
|
+
- 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))
|
|
1522
|
+
|
|
1523
|
+
## [0.39.0] - 2026-01-08
|
|
1524
|
+
|
|
1525
|
+
### Added
|
|
1526
|
+
|
|
1527
|
+
- **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))
|
|
1528
|
+
|
|
1529
|
+
## [0.38.0] - 2026-01-08
|
|
1530
|
+
|
|
1531
|
+
### Added
|
|
1532
|
+
|
|
1533
|
+
- `EditorComponent` interface for custom editor implementations
|
|
1534
|
+
- `StdinBuffer` class to split batched stdin into individual sequences (adapted from [OpenTUI](https://github.com/anomalyco/opentui), MIT license)
|
|
1535
|
+
|
|
1536
|
+
### Fixed
|
|
1537
|
+
|
|
1538
|
+
- Key presses no longer dropped when batched with other events over SSH ([#538](https://github.com/badlogic/pi-mono/pull/538))
|
|
1539
|
+
|
|
1540
|
+
## [0.37.8] - 2026-01-07
|
|
1541
|
+
|
|
1542
|
+
### Added
|
|
1543
|
+
|
|
1544
|
+
- `Component.wantsKeyRelease` property to opt-in to key release events (default false)
|
|
1545
|
+
|
|
1546
|
+
### Fixed
|
|
1547
|
+
|
|
1548
|
+
- TUI now filters out key release events by default, preventing double-processing of keys in editors and other components
|
|
1549
|
+
|
|
1550
|
+
## [0.37.7] - 2026-01-07
|
|
1551
|
+
|
|
1552
|
+
### Fixed
|
|
1553
|
+
|
|
1554
|
+
- `matchesKey()` now correctly matches Kitty protocol sequences for unmodified letter keys (needed for key release events)
|
|
1555
|
+
|
|
1556
|
+
## [0.37.6] - 2026-01-06
|
|
1557
|
+
|
|
1558
|
+
### Added
|
|
1559
|
+
|
|
1560
|
+
- 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.
|
|
1561
|
+
|
|
1562
|
+
## [0.37.0] - 2026-01-05
|
|
1563
|
+
|
|
1564
|
+
### Fixed
|
|
1565
|
+
|
|
1566
|
+
- 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))
|
|
1567
|
+
|
|
1568
|
+
## [0.34.1] - 2026-01-04
|
|
1569
|
+
|
|
1570
|
+
### Added
|
|
1571
|
+
|
|
1572
|
+
- 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))
|
|
1573
|
+
|
|
1574
|
+
## [0.34.0] - 2026-01-04
|
|
1575
|
+
|
|
1576
|
+
### Added
|
|
1577
|
+
|
|
1578
|
+
- `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))
|
|
1579
|
+
|
|
1580
|
+
## [0.33.0] - 2026-01-04
|
|
1581
|
+
|
|
1582
|
+
### Breaking Changes
|
|
1583
|
+
|
|
1584
|
+
- **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))
|
|
1585
|
+
|
|
1586
|
+
### Added
|
|
1587
|
+
|
|
1588
|
+
- `Editor.insertTextAtCursor(text)` method for programmatic text insertion ([#419](https://github.com/badlogic/pi-mono/issues/419))
|
|
1589
|
+
- `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))
|
|
1590
|
+
|
|
1591
|
+
### Changed
|
|
1592
|
+
|
|
1593
|
+
- Key detection refactored: consolidated `is*()` functions into generic `matchesKey(data, keyId)` function that accepts key identifiers like `"ctrl+c"`, `"shift+enter"`, `"alt+left"`, etc.
|
|
1594
|
+
|
|
1595
|
+
## [0.32.2] - 2026-01-03
|
|
1596
|
+
|
|
1597
|
+
### Fixed
|
|
1598
|
+
|
|
1599
|
+
- Slash command autocomplete now triggers for commands starting with `.`, `-`, or `_` (e.g., `/.land`, `/-foo`) ([#422](https://github.com/badlogic/pi-mono/issues/422))
|
|
1600
|
+
|
|
1601
|
+
## [0.32.0] - 2026-01-03
|
|
1602
|
+
|
|
1603
|
+
### Changed
|
|
1604
|
+
|
|
1605
|
+
- 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))
|
|
1606
|
+
|
|
1607
|
+
### Fixed
|
|
1608
|
+
|
|
1609
|
+
- 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))
|
|
1610
|
+
|
|
1341
1611
|
## [0.31.1] - 2026-01-02
|
|
1342
1612
|
|
|
1343
1613
|
### Fixed
|
|
@@ -46,6 +46,13 @@ export declare class Editor implements Component, Focusable {
|
|
|
46
46
|
onSubmit?: (text: string) => void | Promise<void>;
|
|
47
47
|
onAltEnter?: (text: string) => void;
|
|
48
48
|
onChange?: (text: string) => void;
|
|
49
|
+
/** Called for a "marker-sized" paste — the point where the editor would otherwise collapse it
|
|
50
|
+
* into a `[Paste #N]` token (> 10 lines or > 1000 characters). Return `true` to intercept:
|
|
51
|
+
* the editor inserts nothing and records no undo state, leaving insertion to the host (e.g. a
|
|
52
|
+
* "wrap in a code block / XML / attach as file" menu for very large pastes), which re-inserts
|
|
53
|
+
* via {@link insertPaste} or {@link insertText}. Return `false` (or leave unset) for the
|
|
54
|
+
* default collapse-to-marker behavior. `lineCount` is the sanitized paste's line count. */
|
|
55
|
+
onLargePaste?: (text: string, lineCount: number) => boolean;
|
|
49
56
|
onAutocompleteCancel?: () => void;
|
|
50
57
|
disableSubmit: boolean;
|
|
51
58
|
constructor(theme: EditorTheme);
|
|
@@ -106,8 +113,26 @@ export declare class Editor implements Component, Focusable {
|
|
|
106
113
|
setText(text: string): void;
|
|
107
114
|
/** Insert text at the current cursor position */
|
|
108
115
|
insertText(text: string): void;
|
|
116
|
+
/** Delete up to `count` characters immediately before the cursor on the current line.
|
|
117
|
+
* Used to "track back" the auto-repeat spaces that the space-hold push-to-talk gesture
|
|
118
|
+
* optimistically inserts before it recognizes the hold. Capped at the cursor column so it
|
|
119
|
+
* never crosses a line boundary or under-runs the line. */
|
|
120
|
+
deleteBeforeCursor(count: number): void;
|
|
121
|
+
/** Show or replace a volatile speech-to-text preview at the cursor. The text is
|
|
122
|
+
* inserted with undo suspended so a long live dictation never floods the undo
|
|
123
|
+
* stack; finalize it with {@link commitVolatileText} or drop it with
|
|
124
|
+
* {@link clearVolatileText}. Newlines are allowed. */
|
|
125
|
+
setVolatileText(text: string): void;
|
|
126
|
+
/** Remove the current volatile preview without committing it. */
|
|
127
|
+
clearVolatileText(): void;
|
|
128
|
+
/** Drop any volatile preview, then insert `text` as a single undoable edit. */
|
|
129
|
+
commitVolatileText(text: string): void;
|
|
109
130
|
/** Apply terminal paste semantics to text from non-bracketed paste transports. */
|
|
110
131
|
pasteText(text: string): void;
|
|
132
|
+
/** Insert `content` as a collapsed `[Paste #N]` marker (stored for expansion on submit via
|
|
133
|
+
* {@link getExpandedText}). Hosts that intercept large pastes through {@link onLargePaste} use
|
|
134
|
+
* this to re-insert a (possibly transformed) paste without re-triggering the interception hook. */
|
|
135
|
+
insertPaste(content: string): void;
|
|
111
136
|
isShowingAutocomplete(): boolean;
|
|
112
137
|
}
|
|
113
138
|
export {};
|
|
@@ -48,12 +48,22 @@ export declare class ImageBudget {
|
|
|
48
48
|
* gets a fresh id every call.
|
|
49
49
|
*/
|
|
50
50
|
acquireId(key?: string): number;
|
|
51
|
-
/**
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Begin a render pass. Called by the renderer before composing the frame.
|
|
53
|
+
* Pass `stable: true` for a partial/throwaway pass that does not walk the
|
|
54
|
+
* whole tree in display order (the resize viewport fast path): {@link observe}
|
|
55
|
+
* then replays the last committed per-id decision instead of one derived from
|
|
56
|
+
* call order, and the pass must NOT be closed with {@link endPass}.
|
|
57
|
+
*/
|
|
58
|
+
beginPass(stable?: boolean): void;
|
|
53
59
|
/**
|
|
54
60
|
* Record an image in display order and report whether it must render its text
|
|
55
61
|
* fallback this frame. Called by every {@link Image} during render — including
|
|
56
62
|
* on a cache hit, so the image keeps its display-order slot.
|
|
63
|
+
*
|
|
64
|
+
* During a `stable` pass ({@link beginPass}) the call order and visible subset
|
|
65
|
+
* are not authoritative, so the decision is the committed on-terminal split
|
|
66
|
+
* (`#suppressedIds`) keyed by id — order- and partiality-independent.
|
|
57
67
|
*/
|
|
58
68
|
observe(imageId: number): boolean;
|
|
59
69
|
/**
|
|
@@ -130,7 +130,7 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
130
130
|
readonly description: "Undo";
|
|
131
131
|
};
|
|
132
132
|
readonly "tui.input.newLine": {
|
|
133
|
-
readonly defaultKeys: "shift+enter";
|
|
133
|
+
readonly defaultKeys: ["shift+enter", "ctrl+j"];
|
|
134
134
|
readonly description: "Insert newline";
|
|
135
135
|
};
|
|
136
136
|
readonly "tui.input.submit": {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface LoopWatchdogOptions {
|
|
2
|
+
/** How far ahead each probe tick is scheduled, in ms. Default 250. */
|
|
3
|
+
intervalMs?: number;
|
|
4
|
+
/** A tick later than this past its deadline counts as a block. Default 250. */
|
|
5
|
+
thresholdMs?: number;
|
|
6
|
+
/** Monotonic clock source; injectable for tests. Default `performance.now`. */
|
|
7
|
+
now?: () => number;
|
|
8
|
+
/** Timer source; injectable for tests. Default `setTimeout`. */
|
|
9
|
+
schedule?: (cb: () => void, ms: number) => LoopWatchdogTimer;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Timer handle the watchdog arms. `cancel`, when present, is invoked on stop()
|
|
13
|
+
* so a stopped watchdog leaves no armed timer to wake the loop even once.
|
|
14
|
+
*/
|
|
15
|
+
interface LoopWatchdogTimer {
|
|
16
|
+
unref?(): void;
|
|
17
|
+
cancel?(): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead of
|
|
21
|
+
* a recorded deadline; a tick that fires `thresholdMs` past its deadline means
|
|
22
|
+
* the loop was blocked that long. The overshoot is logged once on the rising
|
|
23
|
+
* edge (one block ⇒ one line, deduped via `#wasBlocked`), tagged with the phase
|
|
24
|
+
* active during the elapsed interval via {@link takeRecentLoopPhase} — which
|
|
25
|
+
* survives the synchronous push/pop the instrumented hot paths do before this
|
|
26
|
+
* delayed tick can run — so the stall names its cause instead of "unknown".
|
|
27
|
+
*
|
|
28
|
+
* The handle is `unref`'d so the probe never keeps the process alive, and stop()
|
|
29
|
+
* cancels the armed timer when the handle exposes `cancel` (the default
|
|
30
|
+
* `setTimeout` handle does, via `clearTimeout`). The `#generation` guard remains
|
|
31
|
+
* as a fallback for injected handles that cannot cancel.
|
|
32
|
+
*/
|
|
33
|
+
export declare class LoopWatchdog {
|
|
34
|
+
#private;
|
|
35
|
+
constructor(options?: LoopWatchdogOptions);
|
|
36
|
+
start(): void;
|
|
37
|
+
stop(): void;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -83,14 +83,29 @@ export interface Component {
|
|
|
83
83
|
* of history until it finalizes. Volatile live blocks (tool previews that
|
|
84
84
|
* collapse) omit it. Defaults to `liveRegionStart` when absent; a root that
|
|
85
85
|
* reports no seam at all commits everything that scrolls (shell semantics).
|
|
86
|
+
* `getNativeScrollbackSnapshotSafeEnd` optionally reports a still deeper
|
|
87
|
+
* boundary: the line index up to which the live region is *durable* — its rows
|
|
88
|
+
* may still change bytes later (a streaming markdown table re-aligning its
|
|
89
|
+
* columns every row), but their CURRENT snapshot is permanent content, so
|
|
90
|
+
* dropping them when they scroll above the window is forbidden. Unlike
|
|
91
|
+
* `commitSafeEnd` (byte-stable: offered rows are asserted never to re-layout and
|
|
92
|
+
* stay under the committed-prefix audit), rows committed under the snapshot end
|
|
93
|
+
* are audit-EXEMPT once they pass the window top — the engine appends their
|
|
94
|
+
* scroll-off snapshot and never recommits them, so later layout drift becomes a
|
|
95
|
+
* frozen stale row in history (duplication never loss) instead of either a
|
|
96
|
+
* dropped row or an audit re-anchor spray. Provisional live blocks (collapsing
|
|
97
|
+
* tool/edit previews whose head is a throwaway tail window) omit it. Defaults to
|
|
98
|
+
* `commitSafeEnd ?? liveRegionStart` when absent.
|
|
86
99
|
*
|
|
87
100
|
* When several root children report a seam in the same frame, the topmost
|
|
88
|
-
* one (and its commit-safe extension) defines the boundary:
|
|
89
|
-
* prefix-only, so everything below the first seam is already
|
|
101
|
+
* one (and its commit-safe / snapshot-safe extension) defines the boundary:
|
|
102
|
+
* commits are prefix-only, so everything below the first seam is already
|
|
103
|
+
* excluded.
|
|
90
104
|
*/
|
|
91
105
|
export interface NativeScrollbackLiveRegion {
|
|
92
106
|
getNativeScrollbackLiveRegionStart(): number | undefined;
|
|
93
107
|
getNativeScrollbackCommitSafeEnd?(): number | undefined;
|
|
108
|
+
getNativeScrollbackSnapshotSafeEnd?(): number | undefined;
|
|
94
109
|
}
|
|
95
110
|
export interface NativeScrollbackCommittedRows {
|
|
96
111
|
setNativeScrollbackCommittedRows(rows: number): void;
|
|
@@ -118,6 +133,30 @@ export interface NativeScrollbackCommittedRows {
|
|
|
118
133
|
export interface RenderStablePrefix {
|
|
119
134
|
getRenderStablePrefixRows(): number;
|
|
120
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Opt-in fast path for composing only the visible tail of a tall component
|
|
138
|
+
* during a terminal resize. A drag emits a SIGWINCH burst, and the width
|
|
139
|
+
* changes on every event: a full compose re-lays-out (and, for markdown,
|
|
140
|
+
* re-lexes) the entire transcript per event — O(history) work that is
|
|
141
|
+
* discarded the instant the next event arrives. While the resize is in flight
|
|
142
|
+
* the engine paints only the viewport, so it asks each tall root child for at
|
|
143
|
+
* most `maxRows` rows from the bottom of its render at `width` and skips
|
|
144
|
+
* composing everything above the fold. The authoritative full paint replays
|
|
145
|
+
* once the drag settles (see {@link TUI} resize handling).
|
|
146
|
+
*
|
|
147
|
+
* Contract:
|
|
148
|
+
* - Returns the BOTTOM rows of the component's full render at `width`, in
|
|
149
|
+
* top-to-bottom order, capped at `maxRows` (fewer when the component is
|
|
150
|
+
* shorter). The rows MUST be byte-identical to the corresponding tail of
|
|
151
|
+
* what `render(width)` would have returned, modulo a one-row separator at
|
|
152
|
+
* the very top edge (a transient frame the settle paint overwrites).
|
|
153
|
+
* - MUST NOT mutate any persistent full-compose state: the next `render()`
|
|
154
|
+
* (the settle paint) has to reconcile exactly as if the tail render never
|
|
155
|
+
* happened. Warming pure per-width render caches is fine and desirable.
|
|
156
|
+
*/
|
|
157
|
+
export interface ViewportTailProvider {
|
|
158
|
+
renderViewportTail(width: number, maxRows: number): readonly string[];
|
|
159
|
+
}
|
|
121
160
|
/**
|
|
122
161
|
* Interface for components that can receive focus and display a cursor.
|
|
123
162
|
* When focused, the component should emit CURSOR_MARKER at the cursor position
|
|
@@ -252,7 +291,7 @@ export declare class Container implements Component {
|
|
|
252
291
|
* observationally harmless. Exported for the render-stress harness, whose
|
|
253
292
|
* shadow commit ledger must mirror the engine's law exactly.
|
|
254
293
|
*/
|
|
255
|
-
export declare function findCommittedPrefixResync(frame: readonly string[], prefix: readonly string[]): number;
|
|
294
|
+
export declare function findCommittedPrefixResync(frame: readonly string[], prefix: readonly string[], auditLimit?: number): number;
|
|
256
295
|
/**
|
|
257
296
|
* TUI - Main class for managing terminal UI with differential rendering
|
|
258
297
|
*/
|
|
@@ -270,6 +309,14 @@ export declare class TUI extends Container {
|
|
|
270
309
|
constructor(terminal: Terminal, showHardwareCursor?: boolean, options?: TUIOptions);
|
|
271
310
|
render(width: number): readonly string[];
|
|
272
311
|
get fullRedraws(): number;
|
|
312
|
+
/**
|
|
313
|
+
* Transient viewport-only paints emitted by the non-multiplexer resize fast
|
|
314
|
+
* path. These never touch native scrollback or the commit ledger, so they
|
|
315
|
+
* are counted apart from {@link fullRedraws}.
|
|
316
|
+
*/
|
|
317
|
+
get resizeViewportPaints(): number;
|
|
318
|
+
/** Whether a non-multiplexer resize drag is currently in flight. */
|
|
319
|
+
get resizeViewportActive(): boolean;
|
|
273
320
|
/** Shared budget that caps how many inline images render as live graphics. */
|
|
274
321
|
get imageBudget(): ImageBudget;
|
|
275
322
|
/**
|
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.13.1",
|
|
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.13.1",
|
|
41
|
+
"@oh-my-pi/pi-utils": "15.13.1",
|
|
42
42
|
"lru-cache": "11.5.1",
|
|
43
43
|
"marked": "^18.0.5"
|
|
44
44
|
},
|