diff --git a/codeagent-wrapper/internal/app/cli.go b/codeagent-wrapper/internal/app/cli.go index 2ea139e..162e11f 100644 --- a/codeagent-wrapper/internal/app/cli.go +++ b/codeagent-wrapper/internal/app/cli.go @@ -545,7 +545,7 @@ func runParallelMode(cmd *cobra.Command, args []string, opts *cliOptions, v *vip results[i].CoverageNum = extractCoverageNum(results[i].Coverage) results[i].FilesChanged = extractFilesChangedFromLines(lines) results[i].TestsPassed, results[i].TestsFailed = extractTestResultsFromLines(lines) - results[i].KeyOutput = extractKeyOutputFromLines(lines, 150) + results[i].KeyOutput = extractKeyOutputFromLines(lines, 0) } if err := writeStructuredOutput(outputPath, results); err != nil { diff --git a/codeagent-wrapper/internal/app/utils.go b/codeagent-wrapper/internal/app/utils.go index abec759..55e7145 100644 --- a/codeagent-wrapper/internal/app/utils.go +++ b/codeagent-wrapper/internal/app/utils.go @@ -479,11 +479,19 @@ func extractNumberBefore(s string, idx int) int { } // extractKeyOutputFromLines extracts key output from pre-split lines. +// maxLen=0 means unlimited; maxLen<0 returns "". func extractKeyOutputFromLines(lines []string, maxLen int) string { - if len(lines) == 0 || maxLen <= 0 { + if len(lines) == 0 || maxLen < 0 { return "" } + mayTruncate := func(s string) string { + if maxLen == 0 { + return s + } + return safeTruncate(s, maxLen) + } + // Priority 1: Look for explicit summary lines for _, line := range lines { line = strings.TrimSpace(line) @@ -498,7 +506,7 @@ func extractKeyOutputFromLines(lines []string, maxLen int) string { } content = strings.TrimSpace(content) if len(content) > 0 { - return safeTruncate(content, maxLen) + return mayTruncate(content) } } } @@ -514,10 +522,10 @@ func extractKeyOutputFromLines(lines []string, maxLen int) string { if len(line) < 20 { continue } - return safeTruncate(line, maxLen) + return mayTruncate(line) } - // Fallback: truncate entire message + // Fallback: return entire message clean := strings.TrimSpace(strings.Join(lines, "\n")) - return safeTruncate(clean, maxLen) + return mayTruncate(clean) } diff --git a/codeagent-wrapper/internal/app/utils_test.go b/codeagent-wrapper/internal/app/utils_test.go index 64c3f6b..fd65600 100644 --- a/codeagent-wrapper/internal/app/utils_test.go +++ b/codeagent-wrapper/internal/app/utils_test.go @@ -122,6 +122,33 @@ func TestSafeTruncate(t *testing.T) { } } +func TestExtractKeyOutputFromLines(t *testing.T) { + tests := []struct { + name string + lines []string + maxLen int + want string + }{ + {"empty lines returns empty", []string{}, 0, ""}, + {"negative maxLen returns empty", []string{"hello world"}, -1, ""}, + {"unlimited: summary prefix returned in full", []string{"Summary: all done with a very long description that exceeds 150 characters and should not be cut off at all"}, 0, "all done with a very long description that exceeds 150 characters and should not be cut off at all"}, + {"unlimited: first meaningful line returned in full", []string{"this is a meaningful line that is longer than twenty chars and should not be truncated"}, 0, "this is a meaningful line that is longer than twenty chars and should not be truncated"}, + {"unlimited: skips noise lines", []string{"---", "# heading", "short", "this is a meaningful line longer than twenty chars"}, 0, "this is a meaningful line longer than twenty chars"}, + {"limited: summary prefix truncated", []string{"Summary: hello world truncated"}, 10, "hello w..."}, + {"limited: first meaningful line truncated", []string{"this is a long meaningful line that will be truncated"}, 20, "this is a long me..."}, + {"unlimited: fallback joins all lines", []string{"short", "also short"}, 0, "short\nalso short"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extractKeyOutputFromLines(tt.lines, tt.maxLen) + if got != tt.want { + t.Fatalf("extractKeyOutputFromLines(%v, %d) = %q, want %q", tt.lines, tt.maxLen, got, tt.want) + } + }) + } +} + func TestSanitizeOutput(t *testing.T) { tests := []struct { name string