@gajae-code/tui 0.11.6 → 0.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.7] - 2026-07-22
6
+ ### Fixed
7
+
8
+ - Internal transcript PageUp/PageDown now continues through tool-output and other non-semantic rows instead of intermittently becoming a no-op after a semantic viewport anchor was established.
9
+
10
+ ### Fixed
11
+
12
+ - Spurious resize events with unchanged terminal dimensions (iTerm2 tab switches and window focus changes deliver SIGWINCH without a size change) no longer trigger a forced full redraw. On hosts still using the full clear+replay path (legacy multiplexer opt-in, non-process terminals) that redraw cleared scrollback (`2J`/`H`/`3J`) and replayed the entire transcript, which could park the native viewport at the top of the thread when returning to the tab. `requestResizeRender()` now forces only when the grid size actually changed since the last committed frame; same-size events fall through to a no-op diff render.
13
+
5
14
  ## [0.11.4] - 2026-07-20
6
15
  ### Fixed
7
16
 
@@ -281,6 +281,15 @@ export declare class TUI extends Container {
281
281
  * the transcript top during streaming redraws, so viewport-repaint sessions
282
282
  * keep force off and let `#doRender` repaint only the live viewport. Set
283
283
  * `PI_TUI_LEGACY_MULTIPLEXER_FULL_RENDER=1` to restore the legacy tmux redraw.
284
+ *
285
+ * Spurious resize events (SIGWINCH with unchanged dimensions — iTerm2 tab
286
+ * switches and window focus changes, the self-sent SIGWINCH after resume)
287
+ * must not force either: on hosts still using the `fullRender` path (legacy
288
+ * multiplexer opt-in, non-process terminals) the forced redraw clears
289
+ * scrollback (`2J`/`H`/`3J`) and replays the whole transcript, which can
290
+ * park the native viewport at the transcript top. Only force when the grid
291
+ * size actually changed since the last committed frame; a plain diff render
292
+ * is a no-op otherwise.
284
293
  */
285
294
  requestResizeRender(): void;
286
295
  requestRender(force?: boolean, source?: string): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/tui",
4
- "version": "0.11.6",
4
+ "version": "0.11.7",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -36,8 +36,8 @@
36
36
  "fmt": "biome format --write ."
37
37
  },
38
38
  "dependencies": {
39
- "@gajae-code/natives": "0.11.6",
40
- "@gajae-code/utils": "0.11.6",
39
+ "@gajae-code/natives": "0.11.7",
40
+ "@gajae-code/utils": "0.11.7",
41
41
  "lru-cache": "11.3.6",
42
42
  "marked": "18.0.6"
43
43
  },
package/src/tui.ts CHANGED
@@ -895,7 +895,14 @@ export class TUI extends Container {
895
895
  selected = { row, anchor };
896
896
  }
897
897
  if (selected === undefined) {
898
- if (this.#manualViewportAnchor !== null) return false;
898
+ // A page can consist entirely of non-semantic rows such as tool output,
899
+ // transient panels, or pinned chrome. Fall back to numeric viewport
900
+ // ownership so PageUp/PageDown can continue through those rows instead
901
+ // of becoming an intermittent no-op. A later page with an eligible row
902
+ // will establish a fresh semantic anchor.
903
+ this.#manualViewportAnchor = null;
904
+ this.#manualViewportFallbackAnchors = [];
905
+ this.#reconcileMissingViewportAnchor = false;
899
906
  } else {
900
907
  this.#manualViewportAnchor = {
901
908
  id: selected.anchor.id,
@@ -1339,9 +1346,20 @@ export class TUI extends Container {
1339
1346
  * the transcript top during streaming redraws, so viewport-repaint sessions
1340
1347
  * keep force off and let `#doRender` repaint only the live viewport. Set
1341
1348
  * `PI_TUI_LEGACY_MULTIPLEXER_FULL_RENDER=1` to restore the legacy tmux redraw.
1349
+ *
1350
+ * Spurious resize events (SIGWINCH with unchanged dimensions — iTerm2 tab
1351
+ * switches and window focus changes, the self-sent SIGWINCH after resume)
1352
+ * must not force either: on hosts still using the `fullRender` path (legacy
1353
+ * multiplexer opt-in, non-process terminals) the forced redraw clears
1354
+ * scrollback (`2J`/`H`/`3J`) and replays the whole transcript, which can
1355
+ * park the native viewport at the transcript top. Only force when the grid
1356
+ * size actually changed since the last committed frame; a plain diff render
1357
+ * is a no-op otherwise.
1342
1358
  */
1343
1359
  requestResizeRender(): void {
1344
- this.requestRender(!useViewportRepaintPath(this.terminal), "resize");
1360
+ const dimensionsChanged =
1361
+ this.#previousWidth !== this.terminal.columns || this.#previousHeight !== this.terminal.rows;
1362
+ this.requestRender(dimensionsChanged && !useViewportRepaintPath(this.terminal), "resize");
1345
1363
  }
1346
1364
 
1347
1365
  requestRender(force = false, source = "unknown"): void {