feat: compress repeated terminal output lines

Add Terminal.compressTerminalOutput static method to apply run-length encoding
before truncating terminal output. This significantly reduces output size for
repeated lines while maintaining readability.

- Add compressTerminalOutput static method to Terminal class
- Replace all truncateOutput calls with Terminal.compressTerminalOutput
- Import required functions from extract-text

Test program demonstrating compression:
```python
def generate_repeats():
    patterns = [
        ("A\n", 10),          # 10 lines
        ("AA\n", 100),        # 100 lines
        ("AAA\n", 1000),      # 1K lines
        ("AAAA\n", 10000),    # 10K lines
        ("AAAAA\n", 100000),  # 100K lines
        ("AAAAAA\n", 1000000) # 1M lines
    ]

    for text, count in patterns:
        print(text * count, end="")
```

Sample output showing compression:
```
A
A
A
A
A
A
A
A
A
A
AA
<previous line repeated 99 additional times>
AAA
<previous line repeated 999 additional times>
AAAA
<previous line repeated 9999 additional times>
AAAAA
<previous line repeated 99999 additional times>
AAAAAA
<previous line repeated 999999 additional times>
```

Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
Eric Wheeler 2025-03-09 19:23:58 -07:00
parent 131f9ad0d9
commit 0b4fa0b1d6
2 changed files with 16 additions and 6 deletions

View file

@ -25,9 +25,9 @@ import {
addLineNumbers,
stripLineNumbers,
everyLineHasLineNumbers,
truncateOutput,
} from "../integrations/misc/extract-text"
import { ExitCodeDetails } from "../integrations/terminal/TerminalProcess"
import { Terminal } from "../integrations/terminal/Terminal"
import { TerminalRegistry } from "../integrations/terminal/TerminalRegistry"
import { UrlContentFetcher } from "../services/browser/UrlContentFetcher"
import { listFiles } from "../services/glob/list-files"
@ -968,9 +968,9 @@ export class Cline {
process.on("line", (line) => {
if (!didContinue) {
sendCommandOutput(truncateOutput(line, terminalOutputLineLimit))
sendCommandOutput(Terminal.compressTerminalOutput(line, terminalOutputLineLimit))
} else {
this.say("command_output", truncateOutput(line, terminalOutputLineLimit))
this.say("command_output", Terminal.compressTerminalOutput(line, terminalOutputLineLimit))
}
})
@ -1000,7 +1000,7 @@ export class Cline {
// grouping command_output messages despite any gaps anyways)
await delay(50)
result = truncateOutput(result, terminalOutputLineLimit)
result = Terminal.compressTerminalOutput(result, terminalOutputLineLimit)
if (userFeedback) {
await this.say("user_feedback", userFeedback.text, userFeedback.images)
@ -3546,7 +3546,7 @@ export class Cline {
terminalDetails += `\n## Original command: \`${busyTerminal.getLastCommand()}\``
let newOutput = TerminalRegistry.getUnretrievedOutput(busyTerminal.id)
if (newOutput) {
newOutput = truncateOutput(newOutput, terminalOutputLineLimit)
newOutput = Terminal.compressTerminalOutput(newOutput, terminalOutputLineLimit)
terminalDetails += `\n### New Output\n${newOutput}`
} else {
// details += `\n(Still running, no new output)` // don't want to show this right after running the command
@ -3573,7 +3573,7 @@ export class Cline {
for (const process of completedProcesses) {
let output = process.getUnretrievedOutput()
if (output) {
output = truncateOutput(output, terminalOutputLineLimit)
output = Terminal.compressTerminalOutput(output, terminalOutputLineLimit)
terminalOutputs.push(`Command: \`${process.command}\`\n${output}`)
}
}

View file

@ -1,6 +1,7 @@
import * as vscode from "vscode"
import pWaitFor from "p-wait-for"
import { ExitCodeDetails, mergePromise, TerminalProcess, TerminalProcessResultPromise } from "./TerminalProcess"
import { truncateOutput, applyRunLengthEncoding } from "../misc/extract-text"
export class Terminal {
public terminal: vscode.Terminal
@ -218,4 +219,13 @@ export class Terminal {
throw error
}
}
/**
* Compresses terminal output by applying run-length encoding and truncating to line limit
* @param input The terminal output to compress
* @returns The compressed terminal output
*/
public static compressTerminalOutput(input: string, lineLimit: number): string {
return truncateOutput(applyRunLengthEncoding(input), lineLimit)
}
}