Skip to content

Commit 140ee9d

Browse files
committed
fix: lines dublication, and log pagination
1 parent 7da88fb commit 140ee9d

2 files changed

Lines changed: 19 additions & 6 deletions

File tree

src/cli/tui/routes/workflow/components/output/output-window.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,19 @@ export function OutputWindow(props: OutputWindowProps) {
111111
// Trigger load when near the top (within 3 lines) - skip if already loading
112112
if (scrollTop <= 3 && props.hasMoreAbove && props.onLoadMore && !props.isLoadingEarlier) {
113113
debug('[OutputWindow] Loading earlier lines...')
114+
const scrollHeightBefore = ref.scrollHeight
114115
const linesLoaded = props.onLoadMore()
115116
debug('[OutputWindow] Lines loaded: %d', linesLoaded)
116117
if (linesLoaded > 0) {
117-
ref.scrollTop = linesLoaded // Maintain view position
118+
// Defer scroll adjustment until after render to get accurate measurements
119+
queueMicrotask(() => {
120+
const scrollHeightAfter = ref.scrollHeight
121+
const heightAdded = scrollHeightAfter - scrollHeightBefore
122+
// Maintain view position with small slack (5 lines) to prevent immediate re-trigger
123+
const slack = 5
124+
ref.scrollTop = scrollTop + heightAdded + slack
125+
debug('[OutputWindow] Scroll adjusted: heightAdded=%d, slack=%d, newScrollTop=%d', heightAdded, slack, ref.scrollTop)
126+
})
118127
}
119128
}
120129
}

src/cli/tui/routes/workflow/hooks/useLogStream.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ function readLogFileIncremental(
109109
if (currentSize < state.lastFileSize) {
110110
logDebug('File truncated, doing full read. Old size: %d, new size: %d', state.lastFileSize, currentSize)
111111
const content = readFileSync(path, "utf-8")
112-
const lines = content.split("\n")
112+
// Filter empty lines to match incremental read behavior
113+
const lines = content.split("\n").filter(line => line !== '')
113114
state.lastFileSize = currentSize
114115
state.lastLineCount = lines.length
115116
return {
@@ -123,8 +124,9 @@ function readLogFileIncremental(
123124
// For small files, just do a full read (simpler and fast enough)
124125
if (currentSize < INCREMENTAL_THRESHOLD_BYTES) {
125126
const content = readFileSync(path, "utf-8")
126-
const lines = content.split("\n")
127-
const newLinesCount = lines.length - state.lastLineCount
127+
// Filter empty lines to match incremental read behavior
128+
const lines = content.split("\n").filter(line => line !== '')
129+
const newLinesCount = Math.max(0, lines.length - state.lastLineCount)
128130
state.lastFileSize = currentSize
129131
state.lastLineCount = lines.length
130132
return {
@@ -180,14 +182,15 @@ function readLogFileIncremental(
180182

181183
/**
182184
* Read entire log file (used for initial load or after truncation)
185+
* Filters empty lines to match incremental read behavior
183186
*/
184187
function readLogFileFull(path: string): string[] {
185188
try {
186189
if (!existsSync(path)) {
187190
return []
188191
}
189192
const content = readFileSync(path, "utf-8")
190-
return content.split("\n")
193+
return content.split("\n").filter(line => line !== '')
191194
} catch {
192195
return []
193196
}
@@ -499,8 +502,9 @@ export function useLogStream(
499502
const currentFileSize = getFileSize(logPath)
500503

501504
// Update incremental state
505+
// IMPORTANT: Track RAW line count, not filtered, to match readLogFileIncremental
502506
incrementalState.lastFileSize = currentFileSize
503-
incrementalState.lastLineCount = filteredLines.length
507+
incrementalState.lastLineCount = fileLines.length
504508

505509
// Update windowed state
506510
const trimCount = Math.max(0, filteredLines.length - maxWindow)

0 commit comments

Comments
 (0)