using System.Text; using System.Text.Json; namespace ClaudeDo.Ui.Helpers; public class StreamLineFormatter { private const int MaxLength = 50_000; public string? FormatLine(string line) { JsonDocument doc; try { doc = JsonDocument.Parse(line); } catch (JsonException) { return line; } using (doc) { var root = doc.RootElement; if (!root.TryGetProperty("type", out var typeProp)) return null; var type = typeProp.GetString(); switch (type) { case "stream_event": return FormatStreamEvent(root); case "result": if (root.TryGetProperty("result", out var resultProp)) return $"\n--- Result ---\n{resultProp.GetString()}\n"; return null; case "system": if (root.TryGetProperty("subtype", out var subtypeProp) && subtypeProp.GetString() == "api_retry") return "\n[Retrying API call...]\n"; return null; default: return null; } } } private static string? FormatStreamEvent(JsonElement root) { if (!root.TryGetProperty("event", out var ev)) return null; if (!ev.TryGetProperty("type", out var evTypeProp)) return null; var evType = evTypeProp.GetString(); switch (evType) { case "content_block_delta": if (!ev.TryGetProperty("delta", out var delta)) return null; if (!delta.TryGetProperty("type", out var deltaTypeProp)) return null; var deltaType = deltaTypeProp.GetString(); if (deltaType == "text_delta") { return delta.TryGetProperty("text", out var textProp) ? textProp.GetString() : null; } return null; // input_json_delta and others → skip case "content_block_stop": return "\n"; case "content_block_start": if (!ev.TryGetProperty("content_block", out var cb)) return null; if (cb.TryGetProperty("type", out var cbTypeProp) && cbTypeProp.GetString() == "tool_use" && cb.TryGetProperty("name", out var nameProp)) return $"\n[Tool: {nameProp.GetString()}]\n"; return null; default: return null; // message_start, message_delta, etc. } } public string FormatFile(string filePath) { var sb = new StringBuilder(); foreach (var line in File.ReadLines(filePath)) { var formatted = FormatLine(line); if (formatted is not null) sb.Append(formatted); } return Trim(sb.ToString()); } public static string Trim(string text) { if (text.Length <= MaxLength) return text; var trimStart = text.Length - MaxLength; var newlineAfter = text.IndexOf('\n', trimStart); if (newlineAfter >= 0 && newlineAfter < trimStart + 200) trimStart = newlineAfter + 1; return text[trimStart..]; } }