1use super::*;
2
3pub fn render_self_context(thread_name: &str, episodes: &[EpisodeRecord]) -> Option<String> {
4 if episodes.is_empty() {
5 return None;
6 }
7
8 let mut rendered = format!("Retained history for thread \"{}\":", thread_name);
9 for (index, episode) in episodes.iter().enumerate() {
10 rendered.push_str(&format!(
11 "\n\n=== Episode {} | {} | action: {} ===\n{}",
12 index + 1,
13 episode.created_at,
14 episode.action,
15 episode.content
16 ));
17 }
18 Some(rendered)
19}
20
21pub fn render_source_context(episode: &EpisodeRecord) -> String {
22 format!(
23 "Latest retained episode from thread \"{}\" | {} | action: {}\n{}",
24 episode.thread_name, episode.created_at, episode.action, episode.content
25 )
26}
27
28pub fn render_thread_document(thread_name: &str, episodes: &[EpisodeRecord]) -> String {
29 if episodes.is_empty() {
30 return format!("Thread \"{}\" has no retained episodes.", thread_name);
31 }
32
33 let mut rendered = format!(
34 "Thread \"{}\" retained episodes ({} total):",
35 thread_name,
36 episodes.len()
37 );
38 for (index, episode) in episodes.iter().enumerate() {
39 rendered.push_str(&format!(
40 "\n\n=== Episode {} | {} | action: {} ===\n{}",
41 index + 1,
42 episode.created_at,
43 episode.action,
44 episode.content
45 ));
46 }
47 rendered
48}
49
50pub fn render_workset_document(workset: &WorksetRecord) -> String {
51 let mut rendered = format!(
52 "Workset \"{}\" | status: {} | {} item(s)",
53 workset.id,
54 workset.status,
55 workset.items.len()
56 );
57 rendered.push_str(&format!(
58 "\nsummary: {}",
59 if workset.summary.is_empty() {
60 "(none)"
61 } else {
62 &workset.summary
63 }
64 ));
65 rendered.push_str(&format!("\ngoal: {}", workset.goal));
66 if let Some(recipe) = workset.verification_recipe.as_deref() {
67 rendered.push_str(&format!("\nverification: {}", recipe));
68 }
69 rendered.push_str(&format!(
70 "\ncreated: {} | updated: {}",
71 workset.created_at, workset.updated_at
72 ));
73
74 if workset.items.is_empty() {
75 rendered.push_str("\n\nNo workset items defined.");
76 return rendered;
77 }
78
79 rendered.push_str("\n\nItems:");
80 for item in &workset.items {
81 let dependencies = if item.depends_on.is_empty() {
82 "none".to_string()
83 } else {
84 item.depends_on.join(", ")
85 };
86 if item.status != "planned" {
87 rendered.push_str(&format!(
88 "\n\n{}. [{}|{}] {}",
89 item.position,
90 item.role.to_ascii_uppercase(),
91 item.status.to_ascii_uppercase(),
92 item.title
93 ));
94 } else {
95 rendered.push_str(&format!(
96 "\n\n{}. [{}] {}",
97 item.position, item.role, item.title
98 ));
99 }
100 rendered.push_str(&format!("\n scope: {}", item.scope));
101 rendered.push_str(&format!("\n depends on: {}", dependencies));
102 rendered.push_str(&format!("\n description: {}", item.description));
103 rendered.push_str(&format!("\n acceptance: {}", item.acceptance));
104 if let Some(notes) = item.notes.as_deref() {
105 rendered.push_str(&format!("\n notes: {}", notes));
106 }
107 }
108 rendered
109}
110
111pub fn render_workset_list(worksets: &[WorksetSummary]) -> String {
112 if worksets.is_empty() {
113 return "No worksets in this session.".to_string();
114 }
115
116 let mut rendered = String::from("Worksets:");
117 for workset in worksets {
118 rendered.push_str(&format!(
119 "\n- {} | {} | {} item(s) | updated {}",
120 workset.id, workset.status, workset.item_count, workset.updated_at
121 ));
122 if !workset.summary.is_empty() {
123 rendered.push_str(&format!("\n {}", workset.summary));
124 }
125 }
126 rendered
127}