Merge PR #8444: fix(tui): keep btw panels out of scrollback (@Ant39140)
This commit is contained in:
@@ -31,6 +31,9 @@
|
||||
- Reduced peak memory for persisted subagent revival probes by streaming large file-backed session journals instead of loading the complete journal ([#8117](https://github.com/can1357/oh-my-pi/issues/8117)).
|
||||
- Kept streaming edit previews responsive for large diffs by selecting and highlighting only the visible tail instead of scanning the discarded prefix on every update.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed repeated `/btw` panels committing transient frames to native scrollback and replaying conversation history after dismissal.
|
||||
## [17.3.4] - 2026-08-14
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -390,16 +390,20 @@ export interface InteractiveModeOptions {
|
||||
/**
|
||||
* Anchored live-region container for the HUD/status rows between the transcript
|
||||
* and the editor (working loader, todo + subagent HUDs, transient notification
|
||||
* panels). While it has content every row is live: it reports a seam at 0 so the
|
||||
* engine never commits these anchored, rebuilt-in-place rows to native
|
||||
* scrollback — otherwise stale duplicates pile up above the live copy on short
|
||||
* terminals once the loader sits below a tall HUD. The transcript's own seam,
|
||||
* panels). While it has content every row is live: it reports a seam at 0 and
|
||||
* pins that live region so the engine never commits these anchored,
|
||||
* rebuilt-in-place rows to native scrollback — otherwise stale duplicates pile
|
||||
* up above the live copy on short terminals once the loader sits below a tall HUD. The transcript's own seam,
|
||||
* when present, sits higher and wins (topmost-seam merge in TUI.render).
|
||||
*/
|
||||
class AnchoredLiveContainer extends Container implements NativeScrollbackLiveRegion {
|
||||
getNativeScrollbackLiveRegionStart(): number | undefined {
|
||||
return this.children.length > 0 ? 0 : undefined;
|
||||
}
|
||||
|
||||
isNativeScrollbackLiveRegionPinned(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
||||
import {
|
||||
type Component,
|
||||
Container,
|
||||
CURSOR_MARKER,
|
||||
Editor,
|
||||
type Focusable,
|
||||
type NativeScrollbackCommittedRows,
|
||||
@@ -71,6 +72,10 @@ class AnchoredStatusContainer extends Container implements NativeScrollbackLiveR
|
||||
const hasAnchoredRows = this.children.length > 0;
|
||||
return hasAnchoredRows ? 0 : undefined;
|
||||
}
|
||||
|
||||
isNativeScrollbackLiveRegionPinned(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function strip(rows: string[]): string[] {
|
||||
@@ -351,6 +356,46 @@ describe("TUI.requestComponentRender", () => {
|
||||
await term.flush();
|
||||
}
|
||||
});
|
||||
it("keeps removed pinned panels and repeated transcript copies out of scrollback", async () => {
|
||||
const term = new VirtualTerminal(40, 8, 1_000);
|
||||
const scheduler = new StressRenderScheduler();
|
||||
const tui = new TUI(term, undefined, { renderScheduler: scheduler });
|
||||
const markers = Array.from({ length: 5 }, (_unused, index) => `HIST-${index}`);
|
||||
const transcript = new CountingLines(markers);
|
||||
const status = new AnchoredStatusContainer();
|
||||
const editor = new CountingLines([`editor${CURSOR_MARKER}`]);
|
||||
tui.addChild(transcript);
|
||||
tui.addChild(status);
|
||||
tui.addChild(editor);
|
||||
|
||||
try {
|
||||
tui.start();
|
||||
await scheduler.drain(term);
|
||||
for (let cycle = 1; cycle <= 3; cycle++) {
|
||||
const panel = new CountingLines([`panel-${cycle}-0`]);
|
||||
status.addChild(panel);
|
||||
tui.requestRender();
|
||||
await scheduler.drain(term);
|
||||
for (let tick = 1; tick <= 8; tick++) {
|
||||
panel.set(Array.from({ length: tick + 1 }, (_row, index) => `panel-${cycle}-${tick}-${index}`));
|
||||
tui.requestComponentRender(panel);
|
||||
await scheduler.drain(term);
|
||||
}
|
||||
status.clear();
|
||||
tui.requestRender();
|
||||
await scheduler.drain(term);
|
||||
}
|
||||
|
||||
const buffer = strip(term.getScrollBuffer()).join("\n");
|
||||
for (const marker of markers) {
|
||||
expect(buffer.split(marker)).toHaveLength(2);
|
||||
}
|
||||
expect(buffer).not.toContain("panel-");
|
||||
} finally {
|
||||
tui.stop();
|
||||
await term.flush();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("TUI keystroke-scoped render", () => {
|
||||
|
||||
Reference in New Issue
Block a user