Skip to main content

roder_core/
roadmap.rs

1use roder_api::events::{RoadmapChanged, RoderEvent};
2use roder_roadmap::{
3    Document, DocumentSummary, RoadmapEvent, RoadmapEventKind, ThreadAttachment, ValidationResult,
4};
5
6use crate::Runtime;
7
8impl Runtime {
9    pub async fn list_roadmaps(&self) -> anyhow::Result<Vec<DocumentSummary>> {
10        self.roadmaps.lock().await.list_roadmaps()
11    }
12
13    pub async fn open_roadmap(&self, path: &str) -> anyhow::Result<Document> {
14        let (document, events) = {
15            let mut roadmaps = self.roadmaps.lock().await;
16            let start = roadmaps.events().len();
17            let document = roadmaps.open_roadmap(path)?;
18            let events = roadmaps.events()[start..].to_vec();
19            (document, events)
20        };
21        self.publish_roadmap_events(events).await;
22        Ok(document)
23    }
24
25    pub async fn focus_roadmap_task(&self, path: &str, task_id: &str) -> anyhow::Result<()> {
26        let events = {
27            let mut roadmaps = self.roadmaps.lock().await;
28            let start = roadmaps.events().len();
29            roadmaps.focus_roadmap_task(path, task_id)?;
30            roadmaps.events()[start..].to_vec()
31        };
32        self.publish_roadmap_events(events).await;
33        Ok(())
34    }
35
36    pub async fn set_roadmap_task(
37        &self,
38        path: &str,
39        task_id: &str,
40        checked: bool,
41        evidence: &str,
42    ) -> anyhow::Result<()> {
43        let events = {
44            let mut roadmaps = self.roadmaps.lock().await;
45            let start = roadmaps.events().len();
46            roadmaps.set_roadmap_task(path, task_id, checked, evidence)?;
47            roadmaps.events()[start..].to_vec()
48        };
49        self.publish_roadmap_events(events).await;
50        Ok(())
51    }
52
53    pub async fn validate_roadmap(&self, path: &str) -> anyhow::Result<ValidationResult> {
54        let (result, events) = {
55            let mut roadmaps = self.roadmaps.lock().await;
56            let start = roadmaps.events().len();
57            let result = roadmaps.validate_roadmap(path)?;
58            let events = roadmaps.events()[start..].to_vec();
59            (result, events)
60        };
61        self.publish_roadmap_events(events).await;
62        Ok(result)
63    }
64
65    pub async fn list_roadmap_threads(&self, path: &str) -> anyhow::Result<Vec<ThreadAttachment>> {
66        self.roadmaps.lock().await.list_roadmap_threads(path)
67    }
68
69    pub async fn spawn_roadmap_thread(
70        &self,
71        path: &str,
72        task_id: &str,
73    ) -> anyhow::Result<ThreadAttachment> {
74        let (attachment, events) = {
75            let mut roadmaps = self.roadmaps.lock().await;
76            let start = roadmaps.events().len();
77            let attachment = roadmaps.spawn_roadmap_thread(path, task_id)?;
78            let events = roadmaps.events()[start..].to_vec();
79            (attachment, events)
80        };
81        self.publish_roadmap_events(events).await;
82        Ok(attachment)
83    }
84
85    pub async fn attach_roadmap_thread(
86        &self,
87        path: &str,
88        task_id: &str,
89        thread_id: &str,
90        title: Option<String>,
91    ) -> anyhow::Result<ThreadAttachment> {
92        let (attachment, events) = {
93            let mut roadmaps = self.roadmaps.lock().await;
94            let start = roadmaps.events().len();
95            let attachment = roadmaps.attach_roadmap_thread(path, task_id, thread_id, title)?;
96            let events = roadmaps.events()[start..].to_vec();
97            (attachment, events)
98        };
99        self.publish_roadmap_events(events).await;
100        Ok(attachment)
101    }
102
103    pub async fn enter_roadmap_mode(&self, path: &str) -> anyhow::Result<()> {
104        let events = {
105            let mut roadmaps = self.roadmaps.lock().await;
106            let start = roadmaps.events().len();
107            roadmaps.record_mode_changed(path)?;
108            roadmaps.events()[start..].to_vec()
109        };
110        self.publish_roadmap_events(events).await;
111        Ok(())
112    }
113
114    async fn publish_roadmap_events(&self, events: Vec<RoadmapEvent>) {
115        for event in events {
116            self.emit(RoderEvent::RoadmapChanged(RoadmapChanged {
117                event_kind: roadmap_event_kind(event.kind).to_string(),
118                path: event.path.display().to_string(),
119                task_id: event.task_id,
120                thread_id: event.thread_id,
121                timestamp: event.timestamp,
122            }))
123            .await;
124        }
125    }
126}
127
128fn roadmap_event_kind(kind: RoadmapEventKind) -> &'static str {
129    match kind {
130        RoadmapEventKind::Opened => "opened",
131        RoadmapEventKind::Updated => "updated",
132        RoadmapEventKind::TaskFocused => "task_focused",
133        RoadmapEventKind::TaskChecked => "task_checked",
134        RoadmapEventKind::ThreadAttached => "thread_attached",
135        RoadmapEventKind::ThreadSpawned => "thread_spawned",
136        RoadmapEventKind::Validated => "validated",
137        RoadmapEventKind::ModeChanged => "mode_changed",
138    }
139}