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}