Skip to main content

sac/store/
render.rs

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}