@@ -231,6 +231,7 @@ const (
largeOutputThreshold = 50 * 1024 // 50KB - threshold for saving to file
firstLinesCount = 2
lastLinesCount = 5
+ maxLineLength = 200 // truncate displayed lines to this length
)
func (b *BashTool) makeBashCommand(ctx context.Context, command string, out io.Writer) *exec.Cmd {
@@ -342,19 +343,27 @@ func formatForegroundBashOutput(out string) (string, error) {
result.WriteString("First lines:\n")
firstN := min(firstLinesCount, len(lines))
for i := 0; i < firstN; i++ {
- result.WriteString(fmt.Sprintf("%5d: %s\n", i+1, lines[i]))
+ result.WriteString(fmt.Sprintf("%5d: %s\n", i+1, truncateLine(lines[i])))
}
// Last N lines
result.WriteString("\n...\n\nLast lines:\n")
startIdx := max(0, len(lines)-lastLinesCount)
for i := startIdx; i < len(lines); i++ {
- result.WriteString(fmt.Sprintf("%5d: %s\n", i+1, lines[i]))
+ result.WriteString(fmt.Sprintf("%5d: %s\n", i+1, truncateLine(lines[i])))
}
return result.String(), nil
}
+// truncateLine truncates a line to maxLineLength characters, appending "..." if truncated.
+func truncateLine(line string) string {
+ if len(line) <= maxLineLength {
+ return line
+ }
+ return line[:maxLineLength] + "..."
+}
+
func humanizeBytes(bytes int) string {
switch {
case bytes < 4*1024:
@@ -645,6 +645,39 @@ func TestFormatForegroundBashOutput(t *testing.T) {
t.Logf("Large binary-like output result:\n%s", result)
})
+
+ // Test large output with very long lines (e.g., minified JS)
+ t.Run("Large Output With Long Lines", func(t *testing.T) {
+ // Generate output > 50KB with few very long lines
+ longLine := strings.Repeat("abcdefghij", 1000) // 10KB per line
+ lines := []string{longLine, longLine, longLine, longLine, longLine, longLine}
+ largeOutput := strings.Join(lines, "\n")
+ if len(largeOutput) < largeOutputThreshold {
+ t.Fatalf("Test setup error: output is only %d bytes, need > %d", len(largeOutput), largeOutputThreshold)
+ }
+
+ result, err := formatForegroundBashOutput(largeOutput)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+
+ // Result should be reasonable size (not blow up context)
+ if len(result) > 4096 {
+ t.Errorf("Expected truncated result < 4KB, got %d bytes:\n%s", len(result), result)
+ }
+
+ // Should mention the file
+ if !strings.Contains(result, "saved to:") {
+ t.Errorf("Expected result to mention saved file, got:\n%s", result)
+ }
+
+ // Lines should be truncated
+ if !strings.Contains(result, "...") {
+ t.Errorf("Expected truncated lines with '...', got:\n%s", result)
+ }
+
+ t.Logf("Large output with long lines result:\n%s", result)
+ })
}
// waitForFile waits for a file to exist and be non-empty or times out