diff --git a/strix/interface/tui/internal/render/agent_message.go b/strix/interface/tui/internal/render/agent_message.go index a1ca50aa..6d294853 100644 --- a/strix/interface/tui/internal/render/agent_message.go +++ b/strix/interface/tui/internal/render/agent_message.go @@ -11,8 +11,6 @@ import ( // Markdown (agent_message_renderer.py) // --------------------------------------------------------------------------- -var blankLineRuns = regexp.MustCompile(`\n\s*\n`) - type mdHeader struct { prefix string strip int @@ -33,13 +31,36 @@ func renderAssistantMarkdown(content string) string { if content == "" { return "" } - cleaned := strings.TrimSpace(blankLineRuns.ReplaceAllString(content, "\n\n")) + cleaned := strings.TrimSpace(collapseBlankLines(content)) if cleaned == "" { return "" } return applyMarkdownStyles(cleaned) } +func collapseBlankLines(content string) string { + lines := strings.Split(content, "\n") + out := make([]string, 0, len(lines)) + inCode := false + blank := false + for _, line := range lines { + if strings.HasPrefix(line, "```") { + inCode = !inCode + } + if !inCode && strings.TrimSpace(line) == "" { + if blank { + continue + } + blank = true + out = append(out, "") + continue + } + blank = false + out = append(out, line) + } + return strings.Join(out, "\n") +} + func applyMarkdownStyles(text string) string { var out strings.Builder lines := strings.Split(text, "\n") diff --git a/strix/interface/tui/internal/render/render_test.go b/strix/interface/tui/internal/render/render_test.go index 58a854b2..13474b84 100644 --- a/strix/interface/tui/internal/render/render_test.go +++ b/strix/interface/tui/internal/render/render_test.go @@ -343,3 +343,14 @@ func TestReportSectionsRenderMarkdown(t *testing.T) { } } } + +func TestReportSectionsKeepBlankLinesInFencedCode(t *testing.T) { + body := "Intro.\n\n\n\nRequest:\n```http\nGET /share HTTP/1.1\nHost: target\n\n\nbody\n```\n\n\n\nAfter." + plain := ansi.Strip(renderVulnerabilityReport(map[string]any{"title": "x", "technical_analysis": body}, nil)) + if !strings.Contains(plain, "Host: target\n\n\nbody") { + t.Fatalf("fenced code lost its blank lines in %q", plain) + } + if strings.Contains(plain, "Intro.\n\n\n") || strings.Contains(plain, "\n\n\nAfter.") { + t.Fatalf("blank-line runs outside fenced code were not collapsed in %q", plain) + } +}