@kenkaiiii/ggcoder 4.8.3 → 4.8.4

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.
Files changed (31) hide show
  1. package/dist/ui/App.d.ts +16 -0
  2. package/dist/ui/App.d.ts.map +1 -1
  3. package/dist/ui/App.js +28 -14
  4. package/dist/ui/App.js.map +1 -1
  5. package/dist/ui/atomic-flush-regression.test.d.ts +2 -0
  6. package/dist/ui/atomic-flush-regression.test.d.ts.map +1 -0
  7. package/dist/ui/atomic-flush-regression.test.js +218 -0
  8. package/dist/ui/atomic-flush-regression.test.js.map +1 -0
  9. package/dist/ui/footer-jump-regression.test.js +56 -9
  10. package/dist/ui/footer-jump-regression.test.js.map +1 -1
  11. package/dist/ui/frame-clip-regression.test.d.ts +2 -0
  12. package/dist/ui/frame-clip-regression.test.d.ts.map +1 -0
  13. package/dist/ui/frame-clip-regression.test.js +215 -0
  14. package/dist/ui/frame-clip-regression.test.js.map +1 -0
  15. package/dist/ui/hooks/useTranscriptHistory.d.ts +9 -1
  16. package/dist/ui/hooks/useTranscriptHistory.d.ts.map +1 -1
  17. package/dist/ui/hooks/useTranscriptHistory.js +34 -19
  18. package/dist/ui/hooks/useTranscriptHistory.js.map +1 -1
  19. package/dist/ui/render.d.ts.map +1 -1
  20. package/dist/ui/render.js +126 -1
  21. package/dist/ui/render.js.map +1 -1
  22. package/dist/ui/startup-banner-order.test.d.ts +2 -0
  23. package/dist/ui/startup-banner-order.test.d.ts.map +1 -0
  24. package/dist/ui/startup-banner-order.test.js +105 -0
  25. package/dist/ui/startup-banner-order.test.js.map +1 -0
  26. package/dist/ui/streaming-flush-bounce.test.js +41 -20
  27. package/dist/ui/streaming-flush-bounce.test.js.map +1 -1
  28. package/dist/ui/testing/screen-recorder.d.ts.map +1 -1
  29. package/dist/ui/testing/screen-recorder.js +11 -1
  30. package/dist/ui/testing/screen-recorder.js.map +1 -1
  31. package/package.json +5 -5
@@ -0,0 +1,218 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Full-lifecycle regression for the atomic transcript flush.
3
+ //
4
+ // Models a complete turn on the native-scrollback default: idle → tall
5
+ // streaming response → live tool panel grows under the controls → done. The
6
+ // done transition finalizes the turn the way App does: queueFlush renders the
7
+ // transcript to ANSI and enqueues it through the patched Ink
8
+ // `insertBeforeFrame` while — in the SAME React batch — the live frame shrinks
9
+ // (streamed text flushed, tool panel hidden, activity → done swap). The
10
+ // resulting single frame write is `erase tall frame + scrollback bytes +
11
+ // shorter frame`, so:
12
+ // (a) Ink's full-screen repaint (eraseScreen + cursorTo top) never fires,
13
+ // (b) the footer never moves UP in the terminal buffer, and
14
+ // (c) the controls sit directly under the last transcript row after done —
15
+ // no stranded blank gap.
16
+ import React, { useEffect, useRef, useState } from "react";
17
+ import { render, Text, useStdout } from "ink";
18
+ import { describe, expect, it } from "vitest";
19
+ import stripAnsi from "strip-ansi";
20
+ import { ChatControls, ChatLayout } from "./components/ChatLayout.js";
21
+ import { ChatLivePane } from "./components/ChatLivePane.js";
22
+ import { TerminalSizeProvider } from "./hooks/useTerminalSize.js";
23
+ import { renderTranscriptItem } from "./transcript/TranscriptRenderer.js";
24
+ import { loadTheme, ThemeContext } from "./theme/theme.js";
25
+ import { createTerminalHistoryPrinter } from "./terminal-history.js";
26
+ import { useTranscriptHistory } from "./hooks/useTranscriptHistory.js";
27
+ import { ScreenRecorder, makeRecordingStdout } from "./testing/screen-recorder.js";
28
+ const COLUMNS = 80;
29
+ const ROWS = 24;
30
+ const theme = loadTheme("dark");
31
+ const terminalContext = {
32
+ theme,
33
+ columns: COLUMNS,
34
+ version: "sim",
35
+ model: "sim-model",
36
+ provider: "anthropic",
37
+ cwd: "/tmp/sim-project",
38
+ };
39
+ const FOOTER_BOTTOM = "SIM_ACTIVITY_BAR";
40
+ const TOOL_PANEL_ROWS = 4;
41
+ // Live-area budget: terminal rows minus the worst-case controls block (tool
42
+ // panel + status + input + footer rows). Mirrors App's layout measurement —
43
+ // the clamp is what keeps Ink out of its full-screen tall-frame repaint path.
44
+ const LIVE_AREA_BUDGET = ROWS - (TOOL_PANEL_ROWS + 4) - 2;
45
+ // Taller than the live-area budget, so streaming engages the clamp and the
46
+ // final flush writes more scrollback rows than the live region ever showed.
47
+ const longResponse = Array.from({ length: ROWS - 6 }, (_, i) => `SIM_LINE_${String(i + 1).padStart(2, "0")}`).join("\n");
48
+ function SimulatedControls({ running, toolRows }) {
49
+ return (_jsxs(ChatControls, { controlsRef: () => { }, children: [Array.from({ length: toolRows }, (_, i) => (_jsx(Text, { children: `SIM_TOOL_${i + 1}` }, `tool-${i}`))), _jsx(Text, { children: running ? "SIM_STREAMING" : "SIM_DONE" }), _jsx(Text, { children: "SIM_INPUT" }), _jsx(Text, { children: "SIM_FOOTER" }), _jsx(Text, { children: FOOTER_BOTTOM })] }));
50
+ }
51
+ function Driver({ phase, enqueueStdout }) {
52
+ const { write: writeStdout } = useStdout();
53
+ const [history, setHistory] = useState([]);
54
+ const [liveItems, setLiveItems] = useState([]);
55
+ // All visuals derive from internal state so the done transition can swap
56
+ // EVERYTHING (flush + streamed text removal + panel hide + activity → done)
57
+ // in one effect — i.e. one React batch — exactly like useAgentLoop's onDone.
58
+ const [view, setView] = useState({ running: false, streamingText: "", toolRows: 0 });
59
+ const committedRef = useRef(false);
60
+ // Stable printer across renders — mirrors renderApp, where one printer
61
+ // instance (and its printed-id dedup set) lives for the whole app lifetime.
62
+ const printerRef = useRef(null);
63
+ printerRef.current ??= createTerminalHistoryPrinter();
64
+ const { queueFlush } = useTranscriptHistory({
65
+ terminalHistoryPrinter: printerRef.current,
66
+ terminalHistoryContext: terminalContext,
67
+ writeStdout,
68
+ enqueueStdout,
69
+ sessionPathRef: { current: undefined },
70
+ sessionManagerRef: { current: null },
71
+ history,
72
+ setHistory,
73
+ setLiveItems,
74
+ });
75
+ // Idempotent setter: queueFlush is referentially unstable across renders
76
+ // (it lives in the hook's render scope), so this effect re-runs every
77
+ // commit. Returning the previous object when nothing changed keeps React
78
+ // from looping ("Maximum update depth exceeded") on the stream/tools
79
+ // phases, which set the same view on every run.
80
+ const applyView = (next) => {
81
+ setView((prev) => prev.running === next.running &&
82
+ prev.streamingText === next.streamingText &&
83
+ prev.toolRows === next.toolRows
84
+ ? prev
85
+ : next);
86
+ };
87
+ const applyViewRef = useRef(applyView);
88
+ applyViewRef.current = applyView;
89
+ useEffect(() => {
90
+ if (phase === "idle")
91
+ return;
92
+ if (phase === "stream") {
93
+ applyViewRef.current({ running: true, streamingText: longResponse, toolRows: 0 });
94
+ return;
95
+ }
96
+ if (phase === "tools") {
97
+ applyViewRef.current({
98
+ running: true,
99
+ streamingText: longResponse,
100
+ toolRows: TOOL_PANEL_ROWS,
101
+ });
102
+ return;
103
+ }
104
+ if (committedRef.current)
105
+ return;
106
+ committedRef.current = true;
107
+ // Finalize the turn: enqueue the transcript bytes (passive) and shrink the
108
+ // live frame in the same batch. The next frame write carries both.
109
+ queueFlush([{ kind: "assistant", id: "final", text: longResponse }]);
110
+ setLiveItems([]);
111
+ applyViewRef.current({ running: false, streamingText: "", toolRows: 0 });
112
+ }, [phase, queueFlush]);
113
+ const renderItem = (item, index, items) => renderTranscriptItem({
114
+ item,
115
+ index,
116
+ items,
117
+ version: "sim",
118
+ currentModel: "sim-model",
119
+ currentProvider: "anthropic",
120
+ displayedCwd: "/tmp/sim-project",
121
+ columns: COLUMNS,
122
+ theme,
123
+ renderMarkdown: true,
124
+ measuredLiveAreaRows: LIVE_AREA_BUDGET,
125
+ });
126
+ return (_jsx(ThemeContext.Provider, { value: theme, children: _jsx(TerminalSizeProvider, { children: _jsxs(ChatLayout, { columns: COLUMNS, children: [_jsx(ChatLivePane, { liveItems: liveItems, renderItem: renderItem, isRunning: view.running, visibleStreamingText: view.streamingText, streamingThinking: "", thinkingMs: 0, reserveStreamingSpacing: false, renderMarkdown: true, measuredLiveAreaRows: LIVE_AREA_BUDGET, assistantMarginTop: 0, streamingContinuation: false }), _jsx(SimulatedControls, { running: view.running, toolRows: view.toolRows })] }) }) }));
127
+ }
128
+ const ERASE_SCREEN = "\u001B[2J";
129
+ async function tick() {
130
+ await new Promise((resolve) => setTimeout(resolve, 45));
131
+ }
132
+ describe("atomic transcript flush lifecycle", () => {
133
+ it("finalizes a tool-heavy turn without repaints, footer rises, or gaps", async () => {
134
+ const recorder = new ScreenRecorder({ columns: COLUMNS, rows: ROWS });
135
+ const baseStdout = makeRecordingStdout(recorder);
136
+ const sink = { raw: "" };
137
+ const stdout = new Proxy(baseStdout, {
138
+ get(target, prop, receiver) {
139
+ if (prop === "write") {
140
+ return (chunk, cb) => {
141
+ sink.raw += chunk;
142
+ return target.write(chunk, cb);
143
+ };
144
+ }
145
+ return Reflect.get(target, prop, receiver);
146
+ },
147
+ });
148
+ // Mirrors renderApp's enqueueHistoryWrite: read the (patched) instance at
149
+ // call time, fall back to a raw write when the API is unavailable.
150
+ const instanceRef = {
151
+ current: null,
152
+ };
153
+ const enqueueStdout = (data) => {
154
+ if (instanceRef.current?.insertBeforeFrame) {
155
+ instanceRef.current.insertBeforeFrame(data);
156
+ }
157
+ else {
158
+ stdout.write(data);
159
+ }
160
+ };
161
+ const frames = [];
162
+ const capture = (label) => {
163
+ frames.push({ label, full: stripAnsi(recorder.fullText()) });
164
+ };
165
+ const mounted = render(_jsx(Driver, { phase: "idle", enqueueStdout: enqueueStdout }), {
166
+ stdout,
167
+ columns: COLUMNS,
168
+ rows: ROWS,
169
+ patchConsole: false,
170
+ maxFps: 1000,
171
+ });
172
+ instanceRef.current = mounted;
173
+ await tick();
174
+ capture("idle");
175
+ mounted.rerender(_jsx(Driver, { phase: "stream", enqueueStdout: enqueueStdout }));
176
+ await tick();
177
+ capture("tall streaming");
178
+ mounted.rerender(_jsx(Driver, { phase: "tools", enqueueStdout: enqueueStdout }));
179
+ await tick();
180
+ capture("tool panel grows");
181
+ mounted.rerender(_jsx(Driver, { phase: "done", enqueueStdout: enqueueStdout }));
182
+ await tick();
183
+ capture("done, first settle");
184
+ await tick();
185
+ capture("done, settled");
186
+ mounted.unmount();
187
+ // (a) Zero full-screen repaints (eraseScreen + cursorTo top) across the
188
+ // whole lifecycle — the clamp keeps Ink out of its tall-frame path, and
189
+ // the atomic insert keeps the shrink from ever needing a repaint.
190
+ expect(sink.raw.split(ERASE_SCREEN).length - 1, "full-screen repaints").toBe(0);
191
+ // (b) The footer's absolute row in the terminal buffer never moves UP.
192
+ // Scrollback growth pushes it down; an upward move means a shrink-write
193
+ // landed without its compensating scrollback bytes.
194
+ let previousFooterRow = -1;
195
+ for (const f of frames) {
196
+ const footerRow = f.full.split("\n").findIndex((line) => line.includes(FOOTER_BOTTOM));
197
+ expect(footerRow, `${f.label}: footer present`).toBeGreaterThanOrEqual(0);
198
+ expect(footerRow, `${f.label}: footer buffer row never decreases (was ${previousFooterRow})`).toBeGreaterThanOrEqual(previousFooterRow);
199
+ previousFooterRow = footerRow;
200
+ }
201
+ // (c) After done: the controls sit directly under the last transcript row —
202
+ // no stranded blank rows between the flushed response and the controls.
203
+ const settled = frames.at(-1);
204
+ const lines = settled.full.split("\n");
205
+ const lastTranscriptRow = lines.reduce((acc, line, i) => (line.includes("SIM_LINE_") ? i : acc), -1);
206
+ const controlsRow = lines.findIndex((line) => line.includes("SIM_DONE"));
207
+ expect(lastTranscriptRow, "flushed transcript present after done").toBeGreaterThanOrEqual(0);
208
+ expect(controlsRow, "controls present after done").toBeGreaterThan(lastTranscriptRow);
209
+ const between = lines.slice(lastTranscriptRow + 1, controlsRow);
210
+ expect(between.filter((line) => line.trim().length === 0).length, "no blank gap between transcript and controls").toBe(0);
211
+ // And the flushed response must never be duplicated (scrollback + live).
212
+ for (const f of frames) {
213
+ const occurrences = f.full.split("SIM_LINE_01").length - 1;
214
+ expect(occurrences, `${f.label}: flushed content not duplicated`).toBeLessThanOrEqual(1);
215
+ }
216
+ });
217
+ });
218
+ //# sourceMappingURL=atomic-flush-regression.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-flush-regression.test.js","sourceRoot":"","sources":["../../src/ui/atomic-flush-regression.test.tsx"],"names":[],"mappings":"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"}
@@ -53,15 +53,20 @@ function SimTui({ liveItems, streamingText, controlsLabel, }) {
53
53
  });
54
54
  return (_jsx(ThemeContext.Provider, { value: theme, children: _jsx(TerminalSizeProvider, { children: _jsxs(ChatLayout, { columns: COLUMNS, children: [_jsx(ChatLivePane, { liveItems: liveItems, renderItem: renderItem, isRunning: controlsLabel !== "SIM_DONE", visibleStreamingText: streamingText, streamingThinking: "", thinkingMs: 0, reserveStreamingSpacing: false, renderMarkdown: true, measuredLiveAreaRows: ROWS, assistantMarginTop: 0, streamingContinuation: false }), _jsx(SimulatedControls, { label: controlsLabel })] }) }) }));
55
55
  }
56
- function Driver({ phase }) {
56
+ function Driver({ phase, enqueueStdout }) {
57
57
  const { write: writeStdout } = useStdout();
58
58
  const [history, setHistory] = useState([]);
59
59
  const [liveItems, setLiveItems] = useState([]);
60
60
  const committedRef = useRef(false);
61
+ // Stable printer across renders — mirrors renderApp, where one printer
62
+ // instance (and its printed-id dedup set) lives for the whole app lifetime.
63
+ const printerRef = useRef(null);
64
+ printerRef.current ??= createTerminalHistoryPrinter();
61
65
  const { queueFlush } = useTranscriptHistory({
62
- terminalHistoryPrinter: createTerminalHistoryPrinter(),
66
+ terminalHistoryPrinter: printerRef.current,
63
67
  terminalHistoryContext: terminalContext,
64
68
  writeStdout,
69
+ enqueueStdout,
65
70
  sessionPathRef: { current: undefined },
66
71
  sessionManagerRef: { current: null },
67
72
  history,
@@ -130,25 +135,45 @@ describe("footer jump reproduction", () => {
130
135
  const capture = (label) => {
131
136
  const slice = sink.raw.slice(lastRawLen);
132
137
  lastRawLen = sink.raw.length;
133
- frames.push({ label, lines: viewport(recorder), repaints: countFullRepaints(slice) });
138
+ frames.push({
139
+ label,
140
+ lines: viewport(recorder),
141
+ full: stripAnsi(recorder.fullText()),
142
+ repaints: countFullRepaints(slice),
143
+ });
134
144
  };
135
- const mounted = render(_jsx(Driver, { phase: "idle" }), {
145
+ // Mirrors renderApp's enqueueHistoryWrite: read the (patched) instance at
146
+ // call time, fall back to a raw write when the API is unavailable.
147
+ const instanceRef = {
148
+ current: null,
149
+ };
150
+ const enqueueStdout = (data) => {
151
+ if (instanceRef.current?.insertBeforeFrame) {
152
+ instanceRef.current.insertBeforeFrame(data);
153
+ }
154
+ else {
155
+ stdout.write(data);
156
+ }
157
+ };
158
+ const mounted = render(_jsx(Driver, { phase: "idle", enqueueStdout: enqueueStdout }), {
136
159
  stdout,
137
160
  columns: COLUMNS,
138
161
  rows: ROWS,
139
162
  patchConsole: false,
140
163
  maxFps: 1000,
141
164
  });
165
+ instanceRef.current = mounted;
142
166
  await tick();
143
167
  capture("Z: idle (before first turn)");
144
- mounted.rerender(_jsx(Driver, { phase: "stream-short" }));
168
+ mounted.rerender(_jsx(Driver, { phase: "stream-short", enqueueStdout: enqueueStdout }));
145
169
  await tick();
146
170
  capture("A: short streaming");
147
- mounted.rerender(_jsx(Driver, { phase: "stream-fill" }));
171
+ mounted.rerender(_jsx(Driver, { phase: "stream-fill", enqueueStdout: enqueueStdout }));
148
172
  await tick();
149
173
  capture("B: streaming fills the screen");
150
- mounted.rerender(_jsx(Driver, { phase: "done" }));
174
+ mounted.rerender(_jsx(Driver, { phase: "done", enqueueStdout: enqueueStdout }));
151
175
  await tick();
176
+ capture("C1: done, first settle");
152
177
  await tick();
153
178
  capture("C: done + committed final response");
154
179
  mounted.unmount();
@@ -164,8 +189,30 @@ describe("footer jump reproduction", () => {
164
189
  // repaint (eraseScreen + cursorTo top), which is what visibly shoves the
165
190
  // footer. Some repaints are unavoidable during clamp engagement while
166
191
  // streaming, but committing the finalized response must not repaint.
167
- const doneFrame = frames.find((f) => f.label.startsWith("C:"));
168
- expect(doneFrame?.repaints, "done transition full-screen repaints").toBe(0);
192
+ for (const label of ["C1:", "C:"]) {
193
+ const doneFrame = frames.find((f) => f.label.startsWith(label));
194
+ expect(doneFrame?.repaints, `${label} done transition full-screen repaints`).toBe(0);
195
+ }
196
+ // THE STRAND: the footer's absolute row in the terminal buffer must never
197
+ // move UP across frames. Scrollback growth pushes it down; an upward move
198
+ // means a shrink-write landed without its compensating scrollback bytes —
199
+ // the footer gets stranded mid-screen with blank rows below it. (Measured
200
+ // in the cumulative buffer, not the viewport, so Ink's trailing-newline
201
+ // convention — omitted only for exactly-fullscreen frames — can't skew it.)
202
+ let previousFooterRow = -1;
203
+ for (const f of frames) {
204
+ const bufferLines = f.full.split("\n");
205
+ const footerRow = bufferLines.findIndex((line) => line.includes(FOOTER_BOTTOM));
206
+ expect(footerRow, `${f.label}: footer buffer row never decreases (was ${previousFooterRow})`).toBeGreaterThanOrEqual(previousFooterRow);
207
+ previousFooterRow = footerRow;
208
+ }
209
+ // NO DUPLICATION: the flushed response must never be visible twice (once in
210
+ // scrollback AND still in the live frame). The atomic insert erases the
211
+ // live copy in the same write that adds the scrollback copy.
212
+ for (const f of frames) {
213
+ const occurrences = f.full.split("SIM_LINE_01").length - 1;
214
+ expect(occurrences, `${f.label}: flushed content not duplicated`).toBeLessThanOrEqual(1);
215
+ }
169
216
  // THE START JUMP: with the status slot reserved unconditionally and the
170
217
  // controls height held constant, starting the first turn (idle → first
171
218
  // stream) must not trigger a full-screen repaint either — the footer stays
@@ -1 +1 @@
1
- {"version":3,"file":"footer-jump-regression.test.js","sourceRoot":"","sources":["../../src/ui/footer-jump-regression.test.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"footer-jump-regression.test.js","sourceRoot":"","sources":["../../src/ui/footer-jump-regression.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=frame-clip-regression.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-clip-regression.test.d.ts","sourceRoot":"","sources":["../../src/ui/frame-clip-regression.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,215 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Regression for the mid-screen footer "strand" in scrollback mode.
3
+ //
4
+ // If any single frame reaches terminal height (the app's estimate-based
5
+ // live-area clamp can undercount — emoji widths, wrapped footer lines,
6
+ // transient tool-panel rows), Ink records lastOutputHeight >= rows. On the
7
+ // next SHORTER frame, log-update's eraseLines clamps at the screen top and
8
+ // rewrites the frame top-anchored: the footer lands mid-screen with blank
9
+ // rows below it and stays there. The patched ink's clipFrameToTerminalHeight
10
+ // option (set by ggcoder's scrollback-mode INK_OPTIONS) clips frames to
11
+ // rows - 2 so that poisoned state can never be entered. This test renders a
12
+ // frame that overflows the terminal, then shrinks it, and asserts the footer
13
+ // ends at the bottom of the written content — not stranded above blank rows.
14
+ import React from "react";
15
+ import { render, Text, Box } from "ink";
16
+ import { describe, expect, it } from "vitest";
17
+ import stripAnsi from "strip-ansi";
18
+ import { ScreenRecorder, makeRecordingStdout } from "./testing/screen-recorder.js";
19
+ const COLUMNS = 80;
20
+ const ROWS = 24;
21
+ const FOOTER = "SIM_FOOTER_BOTTOM";
22
+ function Frame({ bodyRows }) {
23
+ return (_jsxs(Box, { flexDirection: "column", width: COLUMNS, children: [Array.from({ length: bodyRows }, (_, i) => (_jsx(Text, { children: `BODY_${String(i + 1).padStart(2, "0")}` }, i))), _jsx(Text, { children: "SIM_INPUT" }), _jsx(Text, { children: FOOTER })] }));
24
+ }
25
+ async function tick() {
26
+ await new Promise((resolve) => setTimeout(resolve, 45));
27
+ }
28
+ describe("scrollback frame clip (clipFrameToTerminalHeight)", () => {
29
+ it("clips overflow frames and never strands the footer above blank rows", async () => {
30
+ const recorder = new ScreenRecorder({ columns: COLUMNS, rows: ROWS });
31
+ const stdout = makeRecordingStdout(recorder);
32
+ // Overflow: 30 body rows + 2 control rows > 24 terminal rows.
33
+ const mounted = render(_jsx(Frame, { bodyRows: 30 }), {
34
+ stdout,
35
+ columns: COLUMNS,
36
+ rows: ROWS,
37
+ patchConsole: false,
38
+ maxFps: 1000,
39
+ // Mirrors ggcoder's scrollback-mode INK_OPTIONS.
40
+ clipFrameToTerminalHeight: true,
41
+ });
42
+ await tick();
43
+ // The clip must keep the frame under terminal height: with rows - 2 = 22
44
+ // frame rows, the oldest body rows are dropped (BODY_01..BODY_10 clipped,
45
+ // mirroring the app's bottom-anchored live-area clamp).
46
+ const tallLines = recorder.viewportLines().map((line) => stripAnsi(line));
47
+ expect(tallLines.some((line) => line.includes("BODY_01"))).toBe(false);
48
+ expect(tallLines.some((line) => line.includes("BODY_30"))).toBe(true);
49
+ expect(tallLines.some((line) => line.includes(FOOTER))).toBe(true);
50
+ // Shrink: the turn ends and the frame collapses to controls + done row.
51
+ // Without the clip this is the poisoned transition (eraseLines clamps at
52
+ // the screen top, frame rewrites top-anchored, footer stranded mid-screen
53
+ // above a block of blank rows).
54
+ mounted.rerender(_jsx(Frame, { bodyRows: 3 }));
55
+ await tick();
56
+ mounted.unmount();
57
+ const lines = recorder.viewportLines().map((line) => stripAnsi(line));
58
+ const footerIdx = lines.findIndex((line) => line.includes(FOOTER));
59
+ const lastNonBlank = lines.reduce((acc, line, i) => (line.trim().length > 0 ? i : acc), -1);
60
+ expect(footerIdx, "footer present after shrink").toBeGreaterThanOrEqual(0);
61
+ expect(lastNonBlank, "no blank rows below the footer (no strand)").toBe(footerIdx);
62
+ });
63
+ });
64
+ describe("scrollback bottom anchoring (anchorFrameToBottom)", () => {
65
+ it("keeps the footer's absolute row fixed when the frame shrinks", async () => {
66
+ const recorder = new ScreenRecorder({ columns: COLUMNS, rows: ROWS });
67
+ const stdout = makeRecordingStdout(recorder);
68
+ // A frame that fits comfortably (12 body + 2 control rows).
69
+ const mounted = render(_jsx(Frame, { bodyRows: 12 }), {
70
+ stdout,
71
+ columns: COLUMNS,
72
+ rows: ROWS,
73
+ patchConsole: false,
74
+ maxFps: 1000,
75
+ // Mirrors ggcoder's scrollback-mode INK_OPTIONS.
76
+ clipFrameToTerminalHeight: true,
77
+ anchorFrameToBottom: true,
78
+ });
79
+ await tick();
80
+ const footerRowAt = () => stripAnsi(recorder.fullText())
81
+ .split("\n")
82
+ .findIndex((line) => line.includes(FOOTER));
83
+ const tallFooterRow = footerRowAt();
84
+ expect(tallFooterRow, "footer present while tall").toBeGreaterThanOrEqual(0);
85
+ // The frame shrinks by 9 rows with no compensating scrollback bytes — the
86
+ // tool-panel-hide / status-swap / finalize scenario. Without anchoring,
87
+ // the footer would move UP by 9 rows; with it, blank pad lines land above
88
+ // the frame and the footer's absolute row stays exactly where it was.
89
+ mounted.rerender(_jsx(Frame, { bodyRows: 3 }));
90
+ await tick();
91
+ expect(footerRowAt(), "footer row unchanged after shrink").toBe(tallFooterRow);
92
+ // Growing again must CONSUME the pad debt: the growth overwrites the
93
+ // blank pad rows above the frame (cursor-up) instead of scrolling new
94
+ // rows, so the footer stays exactly put — not pushed further down — and
95
+ // the gap doesn't survive as permanent whitespace in the transcript.
96
+ mounted.rerender(_jsx(Frame, { bodyRows: 8 }));
97
+ await tick();
98
+ expect(footerRowAt(), "footer row unchanged on regrow (pad consumed)").toBe(tallFooterRow);
99
+ // No stranded blank gap: between the first body row and the footer, every
100
+ // row is real content (the regrown frame reclaimed the pad rows).
101
+ const lines = stripAnsi(recorder.fullText()).split("\n");
102
+ const firstBody = lines.findIndex((line) => line.includes("BODY_01"));
103
+ const footerIdx = lines.findIndex((line) => line.includes(FOOTER));
104
+ const blanksInside = lines
105
+ .slice(firstBody, footerIdx)
106
+ .filter((line) => line.trim().length === 0).length;
107
+ expect(blanksInside, "no permanent blank gap inside the frame region").toBe(0);
108
+ mounted.unmount();
109
+ });
110
+ it("lets the footer return up at idle (anchor inactive — slash menu close)", async () => {
111
+ const recorder = new ScreenRecorder({ columns: COLUMNS, rows: ROWS });
112
+ const stdout = makeRecordingStdout(recorder);
113
+ const mounted = render(_jsx(Frame, { bodyRows: 4 }), {
114
+ stdout,
115
+ columns: COLUMNS,
116
+ rows: ROWS,
117
+ patchConsole: false,
118
+ maxFps: 1000,
119
+ clipFrameToTerminalHeight: true,
120
+ anchorFrameToBottom: true,
121
+ });
122
+ const patched = mounted;
123
+ expect(typeof patched.setFrameAnchorActive, "runtime toggle exposed").toBe("function");
124
+ // Idle: App turns pad creation off (agent not running).
125
+ patched.setFrameAnchorActive(false);
126
+ await tick();
127
+ const footerRowAt = () => stripAnsi(recorder.fullText())
128
+ .split("\n")
129
+ .findIndex((line) => line.includes(FOOTER));
130
+ const baseFooterRow = footerRowAt();
131
+ // Slash menu opens: frame grows by 8 rows — footer moves down.
132
+ mounted.rerender(_jsx(Frame, { bodyRows: 12 }));
133
+ await tick();
134
+ const openFooterRow = footerRowAt();
135
+ expect(openFooterRow, "footer moved down while menu open").toBeGreaterThan(baseFooterRow);
136
+ // Slash menu closes: with the anchor INACTIVE the shrink is symmetric —
137
+ // the footer returns to its pre-menu row and NO pad rows are created.
138
+ mounted.rerender(_jsx(Frame, { bodyRows: 4 }));
139
+ await tick();
140
+ expect(footerRowAt(), "footer returned up after menu close").toBe(baseFooterRow);
141
+ // No whitespace was injected above the frame: the row above BODY_01 in
142
+ // the buffer is not a blank pad line.
143
+ const lines = stripAnsi(recorder.fullText()).split("\n");
144
+ const firstBody = lines.findIndex((line) => line.includes("BODY_01"));
145
+ const blanksInside = lines
146
+ .slice(firstBody, footerRowAt())
147
+ .filter((line) => line.trim().length === 0).length;
148
+ expect(blanksInside, "no pad rows created at idle").toBe(0);
149
+ mounted.unmount();
150
+ });
151
+ it("backfills a bottom-pinned idle shrink with the transcript tail", async () => {
152
+ const recorder = new ScreenRecorder({ columns: COLUMNS, rows: ROWS });
153
+ const stdout = makeRecordingStdout(recorder);
154
+ const mounted = render(_jsx(Frame, { bodyRows: 4 }), {
155
+ stdout,
156
+ columns: COLUMNS,
157
+ rows: ROWS,
158
+ patchConsole: false,
159
+ maxFps: 1000,
160
+ clipFrameToTerminalHeight: true,
161
+ anchorFrameToBottom: true,
162
+ });
163
+ const patched = mounted;
164
+ patched.setFrameAnchorActive(false);
165
+ patched.setFrameShrinkBackfill((rows) => Array.from({ length: rows }, (_, i) => `BACKFILL_${String(i + 1).padStart(2, "0")}`).join("\n"));
166
+ await tick();
167
+ // Fill the screen above the frame with transcript so the frame bottom is
168
+ // pinned at the screen bottom — the chat-in-progress shape.
169
+ patched.insertBeforeFrame(Array.from({ length: ROWS }, (_, i) => `HIST_${String(i + 1).padStart(2, "0")}`).join("\n") +
170
+ "\n");
171
+ // The insert's forced-render fallback fires after 100ms — wait it out so
172
+ // the pinned state is committed before the menu opens.
173
+ await tick();
174
+ await tick();
175
+ await tick();
176
+ const footerRowAt = () => stripAnsi(recorder.fullText())
177
+ .split("\n")
178
+ .findIndex((line) => line.includes(FOOTER));
179
+ const pinnedFooterRow = footerRowAt();
180
+ // Slash menu opens: bottom-pinned idle growth must NOT scroll the
181
+ // terminal — ink repaints the screen in place (cursor home + erase-down +
182
+ // shorter tail + taller frame). A scroll pushes a screenful into native
183
+ // scrollback, and every open/close cycle would deposit one more duplicate
184
+ // copy of those rows (the repeated half-banners). In-place repaint
185
+ // appends NOTHING to the recorder's cumulative buffer — a scroll would
186
+ // grow it by the frame-height delta.
187
+ void pinnedFooterRow;
188
+ const bufferLenBeforeOpen = stripAnsi(recorder.fullText()).split("\n").length;
189
+ mounted.rerender(_jsx(Frame, { bodyRows: 12 }));
190
+ await tick();
191
+ const openLines = stripAnsi(recorder.fullText()).split("\n");
192
+ expect(openLines.length, "menu open repainted in place (no scroll)").toBe(bufferLenBeforeOpen);
193
+ expect(openLines.some((line) => line.includes("BACKFILL_")), "tail visible above the open menu").toBe(true);
194
+ // Slash menu closes: same in-place repaint — taller tail + shorter frame.
195
+ mounted.rerender(_jsx(Frame, { bodyRows: 4 }));
196
+ await tick();
197
+ expect(stripAnsi(recorder.fullText()).split("\n").length, "menu close repainted in place (no scroll)").toBe(bufferLenBeforeOpen);
198
+ // Inspect the visible screen (bottom ROWS of the buffer): footer at the
199
+ // bottom, tail above the frame, no blanks, no duplicated rows.
200
+ const screen = recorder.viewportLines().map((line) => stripAnsi(line));
201
+ const screenFooterIdx = screen.findIndex((line) => line.includes(FOOTER));
202
+ expect(screenFooterIdx, "footer present after repaint").toBeGreaterThanOrEqual(0);
203
+ const lastNonBlank = screen.reduce((acc, line, i) => (line.trim().length > 0 ? i : acc), -1);
204
+ expect(lastNonBlank, "footer is the last content row").toBe(screenFooterIdx);
205
+ // Everything above the frame is transcript tail — each row appears
206
+ // exactly once (no duplicated banner/prompt rows) and none are blank.
207
+ const frameTop = screenFooterIdx - 6; // 4 body + 2 control rows
208
+ const aboveFrame = screen.slice(0, frameTop);
209
+ expect(aboveFrame.every((line) => line.includes("BACKFILL_")), "all rows above the frame are backfill transcript").toBe(true);
210
+ const uniqueRows = new Set(aboveFrame);
211
+ expect(uniqueRows.size, "no duplicated rows above the frame").toBe(aboveFrame.length);
212
+ mounted.unmount();
213
+ });
214
+ });
215
+ //# sourceMappingURL=frame-clip-regression.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-clip-regression.test.js","sourceRoot":"","sources":["../../src/ui/frame-clip-regression.test.tsx"],"names":[],"mappings":"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"}