package main import ( "fmt" "os" "path/filepath" "strings" "go.wit.com/lib/protobuf/chatpb" "go.wit.com/log" ) const termWidth = 120 // The target width for the formatted output boxes. func main() { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: go run format_rich_log.go \n") os.Exit(1) } filename := os.Args[1] data, err := os.ReadFile(filename) if err != nil { log.Fatalf("Error reading file %s: %v", filename, err) } logData, err := chatpb.UnmarshalChatsTEXT(data) if err != nil { log.Fatalf("Error unmarshaling log file %s: %v", filename, err) } // Iterate through the top-level Chat messages, which are now named groups. for _, chat := range logData.GetChats() { fmt.Printf("\n========================================================\n") fmt.Printf("== Chat Topic: %s\n", chat.GetChatName()) fmt.Printf("========================================================\n\n") // Iterate through the entries within this named chat group. for _, entry := range chat.GetEntries() { author := entry.GetFrom().String() // Handle content: prefer content_file, fallback to content. var content string if contentFile := entry.GetContentFile(); contentFile != "" { logDir := filepath.Dir(filename) contentPath := filepath.Join(logDir, contentFile) contentBytes, err := os.ReadFile(contentPath) if err != nil { content = fmt.Sprintf("---\t ERROR: Could not read content file %s: %v ---", contentPath, err) } else { content = string(contentBytes) } } else { content = entry.GetContent() // Fallback for older formats or inline content } // Print the conversational content first. if content != "" { fmt.Printf("✦ %s: %s\n", author, strings.TrimSpace(content)) } // Now, format and print any tool calls. for _, toolCall := range entry.GetToolCalls() { printToolCallBox(toolCall) } // Handle the CodeSnippet field. if snippets := entry.GetSnippets(); snippets != nil { logDir := filepath.Dir(filename) for _, snippet := range snippets { printCodeSnippet(snippet, logDir) } } } } } // printCodeSnippet formats a code snippet block by reading its content from a file. func printCodeSnippet(snippet *chatpb.CodeSnippet, logDir string) { snippetPath := filepath.Join(logDir, snippet.GetFilename()) codeBytes, err := os.ReadFile(snippetPath) if err != nil { fmt.Printf("┌─[ ERROR: Could not read snippet file %s ]─\n\n", snippetPath) return } code := string(codeBytes) language := filepath.Base(snippet.GetFilename()) // Use the filename as the language for display fmt.Printf("┌─[ Code Snippet: %s ]──────────────────────────────────\n", language) // Print each line of the code indented. for _, line := range strings.Split(strings.TrimSpace(code), "\n") { fmt.Printf("│ %s\n", line) } fmt.Printf("└─────────────────────────────────────────────────────────\n\n") } // printToolCallBox handles the decorative formatting for a single tool call. func printToolCallBox(tc *chatpb.ToolCall) { boxWidth := termWidth - 2 // Account for the side borders. // --- Top Border --- fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth)) // --- Header Line --- header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription()) printWrappedLine(header, boxWidth) printEmptyLine(boxWidth) // --- Stdout --- if stdout := tc.GetOutputStdout(); stdout != "" { for _, line := range strings.Split(stdout, "\n") { printWrappedLine(" "+line, boxWidth) } } // --- Stderr --- if stderr := tc.GetOutputStderr(); stderr != "" { for _, line := range strings.Split(stderr, "\n") { printWrappedLine(" "+line, boxWidth) } } printEmptyLine(boxWidth) // --- Bottom Border --- fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth)) } // printWrappedLine prints a line of text, wrapping it if it's too long. func printWrappedLine(text string, width int) { if len(text) == 0 { printEmptyLine(width) return } // Simple wrapping logic. for len(text) > width { fmt.Printf(" │ %-*s │\n", width, text[:width]) text = text[width:] } fmt.Printf(" │ %-*s │\n", width, text) } // printEmptyLine prints a blank line within the box. func printEmptyLine(width int) { fmt.Printf(" │ %*s │\n", width, "") }