oxios_kernel/kernel_handle/
space_api.rs1use serde::{Deserialize, Serialize};
10use std::sync::Arc;
11
12#[allow(unused_imports)]
13use crate::event_bus::EventBus;
14use crate::space::{CrossRefEntry, Space, SpaceManager};
15use anyhow::Context;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19#[allow(missing_docs)]
20pub struct SpaceInfo {
21 pub id: String,
22 pub name: String,
23 pub source: String,
24 pub active: bool,
25 pub paths: Vec<String>,
26 pub interaction_count: u64,
27 pub memory_visible: bool,
28 pub last_active: String,
29}
30
31impl From<&Space> for SpaceInfo {
32 fn from(space: &Space) -> Self {
33 Self {
34 id: space.id.to_string(),
35 name: space.name.clone(),
36 source: space.source.to_string(),
37 active: space.active,
38 paths: space
39 .paths
40 .iter()
41 .map(|p| p.to_string_lossy().to_string())
42 .collect(),
43 interaction_count: space.interaction_count,
44 memory_visible: space.memory_visible,
45 last_active: space.last_active_at.to_rfc3339(),
46 }
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52#[allow(missing_docs)]
53pub struct MemoryFlowInfo {
54 pub from: String,
55 pub to: String,
56 pub flow_type: String,
57 pub entry_count: usize,
58 pub timestamp: String,
59}
60
61impl From<&CrossRefEntry> for MemoryFlowInfo {
62 fn from(entry: &CrossRefEntry) -> Self {
63 Self {
64 from: entry.from.to_string(),
65 to: entry.to.to_string(),
66 flow_type: entry.flow.to_string(),
67 entry_count: entry.entry_ids.len(),
68 timestamp: entry.timestamp.to_rfc3339(),
69 }
70 }
71}
72
73#[allow(dead_code)]
75pub struct SpaceApi {
76 pub(crate) space_manager: Arc<SpaceManager>,
78 #[allow(dead_code)]
80 pub(crate) event_bus: EventBus,
81}
82
83impl SpaceApi {
84 pub fn new(space_manager: Arc<SpaceManager>, event_bus: EventBus) -> Self {
86 Self {
87 space_manager,
88 event_bus,
89 }
90 }
91
92 pub fn list_spaces(&self) -> Vec<SpaceInfo> {
94 self.space_manager
95 .list()
96 .iter()
97 .map(SpaceInfo::from)
98 .collect()
99 }
100
101 pub fn current_space(&self) -> Option<SpaceInfo> {
103 self.space_manager
104 .current_space()
105 .as_ref()
106 .map(SpaceInfo::from)
107 }
108
109 pub async fn get_space(&self, id: &str) -> Option<SpaceInfo> {
111 let space_id = uuid::Uuid::parse_str(id).ok()?;
112 self.space_manager
113 .get_space(&space_id)
114 .await
115 .ok()
116 .flatten()
117 .as_ref()
118 .map(SpaceInfo::from)
119 }
120
121 pub async fn activate(&self, id: &str) -> anyhow::Result<()> {
123 let space_id = uuid::Uuid::parse_str(id).context("Invalid Space ID")?;
124 self.space_manager
125 .activate(&space_id)
126 .await
127 .context("Failed to activate Space")
128 }
129
130 pub async fn archive(&self, id: &str) -> anyhow::Result<()> {
132 let space_id = uuid::Uuid::parse_str(id).context("Invalid Space ID")?;
133
134 let space = self
135 .space_manager
136 .get_space(&space_id)
137 .await?
138 .context("Space not found")?;
139
140 self.space_manager
142 .activate(&self.space_manager.default_space_id())
143 .await?;
144
145 tracing::info!(space_id = %space_id, name = %space.name, "Space archived");
146 Ok(())
147 }
148
149 pub async fn merge(&self, survivor_id: &str, absorbed_id: &str) -> anyhow::Result<()> {
151 let survivor = uuid::Uuid::parse_str(survivor_id).context("Invalid survivor Space ID")?;
152 let absorbed = uuid::Uuid::parse_str(absorbed_id).context("Invalid absorbed Space ID")?;
153
154 self.space_manager
155 .merge_spaces(survivor, absorbed)
156 .await
157 .context("Failed to merge Spaces")
158 }
159
160 pub async fn restore(&self, id: &str) -> anyhow::Result<()> {
162 let space_id = uuid::Uuid::parse_str(id).context("Invalid Space ID")?;
163
164 self.space_manager
165 .restore_from_archive(&space_id)
166 .await
167 .context("Failed to restore Space")
168 }
169
170 pub fn memory_flow(&self) -> Vec<MemoryFlowInfo> {
172 self.space_manager
173 .memory_bridge()
174 .map(|bridge| {
175 bridge
176 .recent_references()
177 .iter()
178 .map(MemoryFlowInfo::from)
179 .collect()
180 })
181 .unwrap_or_default()
182 }
183
184 pub fn workspace_dir(&self, space_id: &uuid::Uuid) -> std::path::PathBuf {
186 self.space_manager.default_workspace_dir(space_id)
187 }
188
189 pub fn memory_flow_for(&self, id: &str) -> Option<Vec<MemoryFlowInfo>> {
191 let space_id = uuid::Uuid::parse_str(id).ok()?;
192 Some(
193 self.space_manager
194 .memory_bridge()?
195 .references_for(space_id)
196 .iter()
197 .map(MemoryFlowInfo::from)
198 .collect(),
199 )
200 }
201}