flake-update-20260201
1package output
2
3import (
4 "fmt"
5 "io"
6 "sort"
7 "strings"
8
9 "github.com/vdemeester/home/tools/review-tool/internal/activity"
10)
11
12// WriteYAML writes the report in YAML format optimized for LLM consumption.
13// YAML format provides better accuracy for LLM understanding compared to JSON or XML.
14func WriteYAML(w io.Writer, report *activity.ReviewReport) error {
15 fmt.Fprintf(w, "# Activity Review: %s\n", report.TimeRange.Description)
16 fmt.Fprintf(w, "period:\n")
17 fmt.Fprintf(w, " start: %s\n", report.TimeRange.Start.Format("2006-01-02"))
18 fmt.Fprintf(w, " end: %s\n", report.TimeRange.End.Format("2006-01-02"))
19 fmt.Fprintf(w, "generated: %s\n", report.GeneratedAt.Format("2006-01-02 15:04"))
20 fmt.Fprintln(w)
21
22 // Summary
23 if report.Summary != nil && report.Summary.TotalItems > 0 {
24 fmt.Fprintln(w, "summary:")
25 fmt.Fprintf(w, " total_activities: %d\n", report.Summary.TotalItems)
26
27 cats := make([]string, 0, len(report.Summary.ItemsByCategory))
28 for cat := range report.Summary.ItemsByCategory {
29 cats = append(cats, cat)
30 }
31 sort.Strings(cats)
32
33 fmt.Fprintln(w, " by_category:")
34 for _, cat := range cats {
35 fmt.Fprintf(w, " %s: %d\n", cat, report.Summary.ItemsByCategory[cat])
36 }
37 fmt.Fprintln(w)
38 }
39
40 // Activities by source
41 fmt.Fprintln(w, "activities:")
42 sourceOrder := []string{"github", "org", "jira", "claude"}
43 for _, source := range sourceOrder {
44 act, ok := report.Activities[source]
45 if !ok || len(act.Items) == 0 {
46 continue
47 }
48
49 fmt.Fprintf(w, " %s:\n", source)
50
51 if act.Error != "" {
52 fmt.Fprintf(w, " error: %q\n", act.Error)
53 continue
54 }
55
56 // Group by type
57 byType := groupByType(act.Items)
58 types := make([]string, 0, len(byType))
59 for t := range byType {
60 types = append(types, t)
61 }
62 sort.Strings(types)
63
64 for _, typ := range types {
65 items := byType[typ]
66 fmt.Fprintf(w, " %s:\n", typ)
67
68 // Sort by timestamp descending
69 sort.Slice(items, func(i, j int) bool {
70 return items[i].Timestamp.After(items[j].Timestamp)
71 })
72
73 for _, item := range items {
74 writeYAMLItem(w, item)
75 }
76 }
77 }
78
79 return nil
80}
81
82func writeYAMLItem(w io.Writer, item activity.ActivityItem) {
83 // Escape title for YAML if needed
84 title := item.Title
85 if strings.ContainsAny(title, ":\n\"'") {
86 title = fmt.Sprintf("%q", title)
87 }
88
89 fmt.Fprintf(w, " - title: %s\n", title)
90 fmt.Fprintf(w, " timestamp: %s\n", item.Timestamp.Format("2006-01-02 15:04"))
91
92 if item.URL != "" {
93 fmt.Fprintf(w, " url: %s\n", item.URL)
94 }
95
96 // Include relevant metadata
97 if section := item.Metadata["section"]; section != "" {
98 fmt.Fprintf(w, " section: %s\n", section)
99 }
100 if file := item.Metadata["file"]; file != "" {
101 // Shorten archive paths
102 if strings.Contains(file, "/archive/") {
103 parts := strings.Split(file, "/archive/")
104 if len(parts) > 1 {
105 fmt.Fprintf(w, " source: archive/%s\n", parts[1])
106 }
107 }
108 }
109 if duration := item.Metadata["duration"]; duration != "" {
110 fmt.Fprintf(w, " duration: %s\n", duration)
111 }
112 if repo := item.Metadata["repo"]; repo != "" {
113 fmt.Fprintf(w, " repo: %s\n", repo)
114 }
115
116 if item.Description != "" {
117 desc := item.Description
118 if strings.ContainsAny(desc, ":\n\"'") {
119 desc = fmt.Sprintf("%q", desc)
120 }
121 fmt.Fprintf(w, " description: %s\n", desc)
122 }
123}