1use crate::logger::Colors;
7use crate::logger::Loggable;
8
9pub struct PipelineSummary {
22 pub total_time: String,
24 pub dev_runs_completed: usize,
26 pub dev_runs_total: usize,
28 pub review_passes_completed: usize,
30 pub review_passes_total: usize,
32 pub review_runs: usize,
34 pub changes_detected: usize,
36 pub isolation_mode: bool,
38 pub verbose: bool,
40 pub review_summary: Option<ReviewSummary>,
42}
43
44pub struct ReviewSummary {
46 pub summary: String,
48 pub unresolved_count: usize,
50 pub blocking_count: usize,
52 pub detailed_breakdown: Option<String>,
54 pub samples: Vec<String>,
56}
57
58pub fn print_welcome_banner(colors: Colors, developer_agent: &str, reviewer_agent: &str) {
68 println!();
69 println!(
70 "{}{}╭────────────────────────────────────────────────────────────╮{}",
71 colors.bold(),
72 colors.cyan(),
73 colors.reset()
74 );
75 println!(
76 "{}{}│{} {}{}🤖 Ralph{} {}─ PROMPT-driven agent orchestrator{} {}{}│{}",
77 colors.bold(),
78 colors.cyan(),
79 colors.reset(),
80 colors.bold(),
81 colors.white(),
82 colors.reset(),
83 colors.dim(),
84 colors.reset(),
85 colors.bold(),
86 colors.cyan(),
87 colors.reset()
88 );
89 println!(
90 "{}{}│{} {}{} × {} pipeline for autonomous development{} {}{}│{}",
91 colors.bold(),
92 colors.cyan(),
93 colors.reset(),
94 colors.dim(),
95 developer_agent,
96 reviewer_agent,
97 colors.reset(),
98 colors.bold(),
99 colors.cyan(),
100 colors.reset()
101 );
102 println!(
103 "{}{}╰────────────────────────────────────────────────────────────╯{}",
104 colors.bold(),
105 colors.cyan(),
106 colors.reset()
107 );
108 println!();
109}
110
111pub fn print_final_summary<L: Loggable>(colors: Colors, summary: &PipelineSummary, logger: &L) {
122 logger.header("Pipeline Complete", crate::logger::Colors::green);
123
124 println!();
125 println!(
126 "{}{}📊 Summary{}",
127 colors.bold(),
128 colors.white(),
129 colors.reset()
130 );
131 println!(
132 "{}──────────────────────────────────{}",
133 colors.dim(),
134 colors.reset()
135 );
136 println!(
137 " {}⏱{} Total time: {}{}{}",
138 colors.cyan(),
139 colors.reset(),
140 colors.bold(),
141 summary.total_time,
142 colors.reset()
143 );
144 println!(
145 " {}🔄{} Dev runs: {}{}{}/{}",
146 colors.blue(),
147 colors.reset(),
148 colors.bold(),
149 summary.dev_runs_completed,
150 colors.reset(),
151 summary.dev_runs_total
152 );
153 println!(
154 " {}🔍{} Review passes: {}{}{}/{}",
155 colors.magenta(),
156 colors.reset(),
157 colors.bold(),
158 summary.review_passes_completed,
159 colors.reset(),
160 summary.review_passes_total
161 );
162 if summary.verbose {
163 println!(
164 " {} {} (Total runs: {}{}{}){}",
165 colors.dim(),
166 colors.magenta(),
167 colors.bold(),
168 summary.review_runs,
169 colors.reset(),
170 colors.reset()
171 );
172 }
173 println!(
174 " {}📝{} Changes detected: {}{}{}",
175 colors.green(),
176 colors.reset(),
177 colors.bold(),
178 summary.changes_detected,
179 colors.reset()
180 );
181
182 if let Some(ref review) = summary.review_summary {
184 print_review_summary(colors, summary.verbose, review);
185 }
186 println!();
187
188 print_output_files(colors, summary.isolation_mode);
189
190 logger.success("Ralph pipeline completed successfully!");
192
193 if summary.review_runs > 0 {
195 logger.info(&format!("Completed {} review run(s)", summary.review_runs));
196 }
197 if summary.changes_detected > 0 {
198 logger.info(&format!("Detected {} change(s)", summary.changes_detected));
199 }
200 if summary.isolation_mode {
201 logger.info("Running in isolation mode");
202 }
203
204 if let Some(ref review) = summary.review_summary {
206 if review.unresolved_count > 0 {
207 logger.warn(&format!(
208 "{} unresolved issue(s) remaining",
209 review.unresolved_count
210 ));
211 }
212 if review.blocking_count > 0 {
213 logger.error(&format!(
214 "{} blocking issue(s) unresolved",
215 review.blocking_count
216 ));
217 }
218 }
219}
220
221fn print_review_summary(colors: Colors, verbose: bool, review: &ReviewSummary) {
223 if review.unresolved_count == 0 && review.blocking_count == 0 {
225 println!(
226 " {}✓{} Review result: {}{}{}",
227 colors.green(),
228 colors.reset(),
229 colors.bold(),
230 review.summary,
231 colors.reset()
232 );
233 return;
234 }
235
236 println!(
238 " {}🔎{} Review summary: {}{}{}",
239 colors.yellow(),
240 colors.reset(),
241 colors.bold(),
242 review.summary,
243 colors.reset()
244 );
245
246 if review.unresolved_count > 0 {
248 println!(
249 " {}⚠{} Unresolved: {}{}{} issues remaining",
250 colors.red(),
251 colors.reset(),
252 colors.bold(),
253 review.unresolved_count,
254 colors.reset()
255 );
256 }
257
258 if verbose {
260 if let Some(ref breakdown) = review.detailed_breakdown {
261 println!(" {}📊{} Breakdown:", colors.dim(), colors.reset());
262 for line in breakdown.lines() {
263 println!(" {}{}{}", colors.dim(), line.trim(), colors.reset());
264 }
265 }
266 if !review.samples.is_empty() {
268 println!(
269 " {}🧾{} Unresolved samples:",
270 colors.dim(),
271 colors.reset()
272 );
273 for s in &review.samples {
274 println!(" {}- {}{}", colors.dim(), s, colors.reset());
275 }
276 }
277 }
278
279 if review.blocking_count > 0 {
281 println!(
282 " {}🚨{} BLOCKING: {}{}{} critical/high issues unresolved",
283 colors.red(),
284 colors.reset(),
285 colors.bold(),
286 review.blocking_count,
287 colors.reset()
288 );
289 }
290}
291
292fn print_output_files(colors: Colors, isolation_mode: bool) {
294 println!(
295 "{}{}📁 Output Files{}",
296 colors.bold(),
297 colors.white(),
298 colors.reset()
299 );
300 println!(
301 "{}──────────────────────────────────{}",
302 colors.dim(),
303 colors.reset()
304 );
305 println!(
306 " → {}PROMPT.md{} Goal definition",
307 colors.cyan(),
308 colors.reset()
309 );
310 println!(
311 " → {}.agent/STATUS.md{} Current status",
312 colors.cyan(),
313 colors.reset()
314 );
315 if !isolation_mode {
317 println!(
318 " → {}.agent/ISSUES.md{} Review findings",
319 colors.cyan(),
320 colors.reset()
321 );
322 println!(
323 " → {}.agent/NOTES.md{} Progress notes",
324 colors.cyan(),
325 colors.reset()
326 );
327 }
328 println!(
329 " → {}.agent/logs/{} Detailed logs",
330 colors.cyan(),
331 colors.reset()
332 );
333 println!();
334}