4runr-os 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mk3-tui/src/app.rs +8 -11
- package/mk3-tui/src/main.rs +8 -5
- package/mk3-tui/src/storage/cache.rs +213 -213
- package/mk3-tui/src/storage/mod.rs +6 -6
- package/mk3-tui/src/ui/agent_builder.rs +921 -921
- package/mk3-tui/src/ui/layout.rs +65 -3
- package/mk3-tui/src/ui/run_manager.rs +676 -676
- package/mk3-tui/src/ui/settings.rs +362 -362
- package/mk3-tui/src/websocket.rs +303 -303
- package/package.json +1 -1
package/mk3-tui/src/app.rs
CHANGED
|
@@ -383,8 +383,14 @@ impl App {
|
|
|
383
383
|
self.state.logs.push_back(" ESC - Close overlay/popup or clear input".into());
|
|
384
384
|
self.state.logs.push_back("".into());
|
|
385
385
|
|
|
386
|
-
//
|
|
387
|
-
self.state.logs.push_back("[HELP]
|
|
386
|
+
// Screen Controls
|
|
387
|
+
self.state.logs.push_back("[HELP] Screen Controls:".into());
|
|
388
|
+
self.state.logs.push_back(" Agent Builder: Enter=Next, Backspace=Prev, ESC=Cancel".into());
|
|
389
|
+
self.state.logs.push_back(" Run Manager: ↑/↓=Navigate, F=Filter, S=Sort, R=Refresh".into());
|
|
390
|
+
self.state.logs.push_back(" Settings: ↑/↓=Navigate, Space=Toggle, Enter=Save".into());
|
|
391
|
+
self.state.logs.push_back("".into());
|
|
392
|
+
|
|
393
|
+
// WebSocket Commands - Label BEFORE separator
|
|
388
394
|
self.state.logs.push_back("[HELP] WebSocket Commands (requires connection):".into());
|
|
389
395
|
self.state.logs.push_back("[HELP] ─────────────────────────────────────────".into());
|
|
390
396
|
self.state.logs.push_back(" agent.list - List all agents".into());
|
|
@@ -396,12 +402,6 @@ impl App {
|
|
|
396
402
|
self.state.logs.push_back(" tool.list - List available tools".into());
|
|
397
403
|
self.state.logs.push_back("".into());
|
|
398
404
|
|
|
399
|
-
// Screen Controls
|
|
400
|
-
self.state.logs.push_back("[HELP] Screen Controls:".into());
|
|
401
|
-
self.state.logs.push_back(" Agent Builder: Enter=Next, Backspace=Prev, ESC=Cancel".into());
|
|
402
|
-
self.state.logs.push_back(" Run Manager: ↑/↓=Navigate, F=Filter, S=Sort, R=Refresh".into());
|
|
403
|
-
self.state.logs.push_back(" Settings: ↑/↓=Navigate, Space=Toggle, Enter=Save".into());
|
|
404
|
-
self.state.logs.push_back("".into());
|
|
405
405
|
self.state.logs.push_back("[HELP] Press F12 to toggle performance overlay".into());
|
|
406
406
|
self.state.logs.push_back("[HELP] ═══════════════════════════════════════".into());
|
|
407
407
|
}
|
|
@@ -1034,20 +1034,17 @@ impl App {
|
|
|
1034
1034
|
// Filter
|
|
1035
1035
|
KeyCode::Char('f') | KeyCode::Char('F') => {
|
|
1036
1036
|
self.state.run_manager.next_filter();
|
|
1037
|
-
self.add_log(format!("[RUN] Filter: {}", self.state.run_manager.filter.as_str()));
|
|
1038
1037
|
self.request_render("run_manager_filter");
|
|
1039
1038
|
}
|
|
1040
1039
|
|
|
1041
1040
|
// Sort
|
|
1042
1041
|
KeyCode::Char('s') | KeyCode::Char('S') => {
|
|
1043
1042
|
self.state.run_manager.next_sort();
|
|
1044
|
-
self.add_log(format!("[RUN] Sort: {}", self.state.run_manager.sort.as_str()));
|
|
1045
1043
|
self.request_render("run_manager_sort");
|
|
1046
1044
|
}
|
|
1047
1045
|
|
|
1048
1046
|
// Refresh
|
|
1049
1047
|
KeyCode::Char('r') | KeyCode::Char('R') => {
|
|
1050
|
-
self.add_log("[RUN] Refreshing run list...".to_string());
|
|
1051
1048
|
// TODO: Send run.list command via WebSocket
|
|
1052
1049
|
self.request_render("run_manager_refresh");
|
|
1053
1050
|
}
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -172,11 +172,14 @@ fn main() -> Result<()> {
|
|
|
172
172
|
let _ = cache.update_agents(agents);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
// Only log if agents were actually loaded
|
|
176
|
+
if agents_array.len() > 0 {
|
|
177
|
+
app.add_log(format!(
|
|
178
|
+
"✓ [{}] Loaded {} agents",
|
|
179
|
+
short_id,
|
|
180
|
+
agents_array.len()
|
|
181
|
+
));
|
|
182
|
+
}
|
|
180
183
|
}
|
|
181
184
|
} else {
|
|
182
185
|
app.add_log(format!("✓ [{}] Success", short_id));
|
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
/// Cache implementation for local data storage
|
|
2
|
-
/// Stores agents, runs, and system status in JSON format
|
|
3
|
-
|
|
4
|
-
use serde::{Deserialize, Serialize};
|
|
5
|
-
use std::fs;
|
|
6
|
-
use std::path::PathBuf;
|
|
7
|
-
use std::time::{SystemTime, UNIX_EPOCH};
|
|
8
|
-
|
|
9
|
-
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
10
|
-
pub struct AgentData {
|
|
11
|
-
pub name: String,
|
|
12
|
-
pub description: Option<String>,
|
|
13
|
-
pub model: String,
|
|
14
|
-
pub provider: String,
|
|
15
|
-
pub created_at: u64,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
19
|
-
pub struct RunData {
|
|
20
|
-
pub id: String,
|
|
21
|
-
pub name: String,
|
|
22
|
-
pub agent: String,
|
|
23
|
-
pub status: String,
|
|
24
|
-
pub started_at: u64,
|
|
25
|
-
pub duration: Option<u64>,
|
|
26
|
-
pub tokens_used: Option<u64>,
|
|
27
|
-
pub cost: Option<f64>,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
31
|
-
pub struct SystemStatusData {
|
|
32
|
-
pub connected: bool,
|
|
33
|
-
pub gateway_url: Option<String>,
|
|
34
|
-
pub posture: String,
|
|
35
|
-
pub last_updated: u64,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
39
|
-
pub struct CacheData {
|
|
40
|
-
pub agents: Vec<AgentData>,
|
|
41
|
-
pub runs: Vec<RunData>,
|
|
42
|
-
pub system_status: Option<SystemStatusData>,
|
|
43
|
-
pub last_updated: u64,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#[derive(Debug, Clone)]
|
|
47
|
-
pub struct Cache {
|
|
48
|
-
cache_path: PathBuf,
|
|
49
|
-
data: CacheData,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
impl Cache {
|
|
53
|
-
/// Create a new cache instance
|
|
54
|
-
pub fn new() -> Result<Self, std::io::Error> {
|
|
55
|
-
let cache_dir = Self::get_cache_dir()?;
|
|
56
|
-
fs::create_dir_all(&cache_dir)?;
|
|
57
|
-
|
|
58
|
-
let cache_path = cache_dir.join("4runr_cache.json");
|
|
59
|
-
let data = Self::load_from_file(&cache_path)?;
|
|
60
|
-
|
|
61
|
-
Ok(Self { cache_path, data })
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/// Get the cache directory path
|
|
65
|
-
fn get_cache_dir() -> Result<PathBuf, std::io::Error> {
|
|
66
|
-
#[cfg(target_os = "windows")]
|
|
67
|
-
{
|
|
68
|
-
let appdata = std::env::var("APPDATA")
|
|
69
|
-
.unwrap_or_else(|_| String::from("C:\\Users\\Default\\AppData\\Roaming"));
|
|
70
|
-
Ok(PathBuf::from(appdata).join("4runr"))
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
#[cfg(not(target_os = "windows"))]
|
|
74
|
-
{
|
|
75
|
-
let home = std::env::var("HOME")
|
|
76
|
-
.unwrap_or_else(|_| String::from("/tmp"));
|
|
77
|
-
Ok(PathBuf::from(home).join(".4runr"))
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/// Load cache from file
|
|
82
|
-
fn load_from_file(path: &PathBuf) -> Result<CacheData, std::io::Error> {
|
|
83
|
-
if !path.exists() {
|
|
84
|
-
return Ok(CacheData::default());
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let contents = fs::read_to_string(path)?;
|
|
88
|
-
let data: CacheData = serde_json::from_str(&contents)
|
|
89
|
-
.unwrap_or_default();
|
|
90
|
-
|
|
91
|
-
Ok(data)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/// Save cache to file
|
|
95
|
-
fn save_to_file(&self) -> Result<(), std::io::Error> {
|
|
96
|
-
let json = serde_json::to_string_pretty(&self.data)?;
|
|
97
|
-
fs::write(&self.cache_path, json)?;
|
|
98
|
-
Ok(())
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/// Get current timestamp
|
|
102
|
-
fn now() -> u64 {
|
|
103
|
-
SystemTime::now()
|
|
104
|
-
.duration_since(UNIX_EPOCH)
|
|
105
|
-
.unwrap()
|
|
106
|
-
.as_secs()
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// === Agent Operations ===
|
|
110
|
-
|
|
111
|
-
/// Get all cached agents
|
|
112
|
-
pub fn get_agents(&self) -> Vec<AgentData> {
|
|
113
|
-
self.data.agents.clone()
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/// Update agents cache
|
|
117
|
-
pub fn update_agents(&mut self, agents: Vec<AgentData>) -> Result<(), std::io::Error> {
|
|
118
|
-
self.data.agents = agents;
|
|
119
|
-
self.data.last_updated = Self::now();
|
|
120
|
-
self.save_to_file()
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/// Add a single agent
|
|
124
|
-
pub fn add_agent(&mut self, agent: AgentData) -> Result<(), std::io::Error> {
|
|
125
|
-
self.data.agents.push(agent);
|
|
126
|
-
self.data.last_updated = Self::now();
|
|
127
|
-
self.save_to_file()
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/// Remove an agent by name
|
|
131
|
-
pub fn remove_agent(&mut self, name: &str) -> Result<(), std::io::Error> {
|
|
132
|
-
self.data.agents.retain(|a| a.name != name);
|
|
133
|
-
self.data.last_updated = Self::now();
|
|
134
|
-
self.save_to_file()
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// === Run Operations ===
|
|
138
|
-
|
|
139
|
-
/// Get all cached runs
|
|
140
|
-
pub fn get_runs(&self) -> Vec<RunData> {
|
|
141
|
-
self.data.runs.clone()
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/// Update runs cache
|
|
145
|
-
pub fn update_runs(&mut self, runs: Vec<RunData>) -> Result<(), std::io::Error> {
|
|
146
|
-
self.data.runs = runs;
|
|
147
|
-
self.data.last_updated = Self::now();
|
|
148
|
-
self.save_to_file()
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/// Add a single run
|
|
152
|
-
pub fn add_run(&mut self, run: RunData) -> Result<(), std::io::Error> {
|
|
153
|
-
self.data.runs.push(run);
|
|
154
|
-
self.data.last_updated = Self::now();
|
|
155
|
-
self.save_to_file()
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/// Update a run by ID
|
|
159
|
-
pub fn update_run(&mut self, id: &str, run: RunData) -> Result<(), std::io::Error> {
|
|
160
|
-
if let Some(existing) = self.data.runs.iter_mut().find(|r| r.id == id) {
|
|
161
|
-
*existing = run;
|
|
162
|
-
self.data.last_updated = Self::now();
|
|
163
|
-
self.save_to_file()?;
|
|
164
|
-
}
|
|
165
|
-
Ok(())
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// === System Status Operations ===
|
|
169
|
-
|
|
170
|
-
/// Get cached system status
|
|
171
|
-
pub fn get_system_status(&self) -> Option<SystemStatusData> {
|
|
172
|
-
self.data.system_status.clone()
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/// Update system status cache
|
|
176
|
-
pub fn update_system_status(&mut self, status: SystemStatusData) -> Result<(), std::io::Error> {
|
|
177
|
-
self.data.system_status = Some(status);
|
|
178
|
-
self.data.last_updated = Self::now();
|
|
179
|
-
self.save_to_file()
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// === Cache Management ===
|
|
183
|
-
|
|
184
|
-
/// Get cache age in seconds
|
|
185
|
-
pub fn get_age(&self) -> u64 {
|
|
186
|
-
Self::now().saturating_sub(self.data.last_updated)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/// Check if cache is stale (older than threshold)
|
|
190
|
-
pub fn is_stale(&self, threshold_secs: u64) -> bool {
|
|
191
|
-
self.get_age() > threshold_secs
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/// Clear all cached data
|
|
195
|
-
pub fn clear(&mut self) -> Result<(), std::io::Error> {
|
|
196
|
-
self.data = CacheData::default();
|
|
197
|
-
self.save_to_file()
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/// Get cache data reference
|
|
201
|
-
pub fn data(&self) -> &CacheData {
|
|
202
|
-
&self.data
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
impl Default for Cache {
|
|
207
|
-
fn default() -> Self {
|
|
208
|
-
Self::new().unwrap_or_else(|_| Self {
|
|
209
|
-
cache_path: PathBuf::from("4runr_cache.json"),
|
|
210
|
-
data: CacheData::default(),
|
|
211
|
-
})
|
|
212
|
-
}
|
|
213
|
-
}
|
|
1
|
+
/// Cache implementation for local data storage
|
|
2
|
+
/// Stores agents, runs, and system status in JSON format
|
|
3
|
+
|
|
4
|
+
use serde::{Deserialize, Serialize};
|
|
5
|
+
use std::fs;
|
|
6
|
+
use std::path::PathBuf;
|
|
7
|
+
use std::time::{SystemTime, UNIX_EPOCH};
|
|
8
|
+
|
|
9
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
10
|
+
pub struct AgentData {
|
|
11
|
+
pub name: String,
|
|
12
|
+
pub description: Option<String>,
|
|
13
|
+
pub model: String,
|
|
14
|
+
pub provider: String,
|
|
15
|
+
pub created_at: u64,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
19
|
+
pub struct RunData {
|
|
20
|
+
pub id: String,
|
|
21
|
+
pub name: String,
|
|
22
|
+
pub agent: String,
|
|
23
|
+
pub status: String,
|
|
24
|
+
pub started_at: u64,
|
|
25
|
+
pub duration: Option<u64>,
|
|
26
|
+
pub tokens_used: Option<u64>,
|
|
27
|
+
pub cost: Option<f64>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
31
|
+
pub struct SystemStatusData {
|
|
32
|
+
pub connected: bool,
|
|
33
|
+
pub gateway_url: Option<String>,
|
|
34
|
+
pub posture: String,
|
|
35
|
+
pub last_updated: u64,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
39
|
+
pub struct CacheData {
|
|
40
|
+
pub agents: Vec<AgentData>,
|
|
41
|
+
pub runs: Vec<RunData>,
|
|
42
|
+
pub system_status: Option<SystemStatusData>,
|
|
43
|
+
pub last_updated: u64,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[derive(Debug, Clone)]
|
|
47
|
+
pub struct Cache {
|
|
48
|
+
cache_path: PathBuf,
|
|
49
|
+
data: CacheData,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
impl Cache {
|
|
53
|
+
/// Create a new cache instance
|
|
54
|
+
pub fn new() -> Result<Self, std::io::Error> {
|
|
55
|
+
let cache_dir = Self::get_cache_dir()?;
|
|
56
|
+
fs::create_dir_all(&cache_dir)?;
|
|
57
|
+
|
|
58
|
+
let cache_path = cache_dir.join("4runr_cache.json");
|
|
59
|
+
let data = Self::load_from_file(&cache_path)?;
|
|
60
|
+
|
|
61
|
+
Ok(Self { cache_path, data })
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Get the cache directory path
|
|
65
|
+
fn get_cache_dir() -> Result<PathBuf, std::io::Error> {
|
|
66
|
+
#[cfg(target_os = "windows")]
|
|
67
|
+
{
|
|
68
|
+
let appdata = std::env::var("APPDATA")
|
|
69
|
+
.unwrap_or_else(|_| String::from("C:\\Users\\Default\\AppData\\Roaming"));
|
|
70
|
+
Ok(PathBuf::from(appdata).join("4runr"))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
#[cfg(not(target_os = "windows"))]
|
|
74
|
+
{
|
|
75
|
+
let home = std::env::var("HOME")
|
|
76
|
+
.unwrap_or_else(|_| String::from("/tmp"));
|
|
77
|
+
Ok(PathBuf::from(home).join(".4runr"))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Load cache from file
|
|
82
|
+
fn load_from_file(path: &PathBuf) -> Result<CacheData, std::io::Error> {
|
|
83
|
+
if !path.exists() {
|
|
84
|
+
return Ok(CacheData::default());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let contents = fs::read_to_string(path)?;
|
|
88
|
+
let data: CacheData = serde_json::from_str(&contents)
|
|
89
|
+
.unwrap_or_default();
|
|
90
|
+
|
|
91
|
+
Ok(data)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Save cache to file
|
|
95
|
+
fn save_to_file(&self) -> Result<(), std::io::Error> {
|
|
96
|
+
let json = serde_json::to_string_pretty(&self.data)?;
|
|
97
|
+
fs::write(&self.cache_path, json)?;
|
|
98
|
+
Ok(())
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/// Get current timestamp
|
|
102
|
+
fn now() -> u64 {
|
|
103
|
+
SystemTime::now()
|
|
104
|
+
.duration_since(UNIX_EPOCH)
|
|
105
|
+
.unwrap()
|
|
106
|
+
.as_secs()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// === Agent Operations ===
|
|
110
|
+
|
|
111
|
+
/// Get all cached agents
|
|
112
|
+
pub fn get_agents(&self) -> Vec<AgentData> {
|
|
113
|
+
self.data.agents.clone()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// Update agents cache
|
|
117
|
+
pub fn update_agents(&mut self, agents: Vec<AgentData>) -> Result<(), std::io::Error> {
|
|
118
|
+
self.data.agents = agents;
|
|
119
|
+
self.data.last_updated = Self::now();
|
|
120
|
+
self.save_to_file()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Add a single agent
|
|
124
|
+
pub fn add_agent(&mut self, agent: AgentData) -> Result<(), std::io::Error> {
|
|
125
|
+
self.data.agents.push(agent);
|
|
126
|
+
self.data.last_updated = Self::now();
|
|
127
|
+
self.save_to_file()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Remove an agent by name
|
|
131
|
+
pub fn remove_agent(&mut self, name: &str) -> Result<(), std::io::Error> {
|
|
132
|
+
self.data.agents.retain(|a| a.name != name);
|
|
133
|
+
self.data.last_updated = Self::now();
|
|
134
|
+
self.save_to_file()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// === Run Operations ===
|
|
138
|
+
|
|
139
|
+
/// Get all cached runs
|
|
140
|
+
pub fn get_runs(&self) -> Vec<RunData> {
|
|
141
|
+
self.data.runs.clone()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Update runs cache
|
|
145
|
+
pub fn update_runs(&mut self, runs: Vec<RunData>) -> Result<(), std::io::Error> {
|
|
146
|
+
self.data.runs = runs;
|
|
147
|
+
self.data.last_updated = Self::now();
|
|
148
|
+
self.save_to_file()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// Add a single run
|
|
152
|
+
pub fn add_run(&mut self, run: RunData) -> Result<(), std::io::Error> {
|
|
153
|
+
self.data.runs.push(run);
|
|
154
|
+
self.data.last_updated = Self::now();
|
|
155
|
+
self.save_to_file()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// Update a run by ID
|
|
159
|
+
pub fn update_run(&mut self, id: &str, run: RunData) -> Result<(), std::io::Error> {
|
|
160
|
+
if let Some(existing) = self.data.runs.iter_mut().find(|r| r.id == id) {
|
|
161
|
+
*existing = run;
|
|
162
|
+
self.data.last_updated = Self::now();
|
|
163
|
+
self.save_to_file()?;
|
|
164
|
+
}
|
|
165
|
+
Ok(())
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// === System Status Operations ===
|
|
169
|
+
|
|
170
|
+
/// Get cached system status
|
|
171
|
+
pub fn get_system_status(&self) -> Option<SystemStatusData> {
|
|
172
|
+
self.data.system_status.clone()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// Update system status cache
|
|
176
|
+
pub fn update_system_status(&mut self, status: SystemStatusData) -> Result<(), std::io::Error> {
|
|
177
|
+
self.data.system_status = Some(status);
|
|
178
|
+
self.data.last_updated = Self::now();
|
|
179
|
+
self.save_to_file()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// === Cache Management ===
|
|
183
|
+
|
|
184
|
+
/// Get cache age in seconds
|
|
185
|
+
pub fn get_age(&self) -> u64 {
|
|
186
|
+
Self::now().saturating_sub(self.data.last_updated)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// Check if cache is stale (older than threshold)
|
|
190
|
+
pub fn is_stale(&self, threshold_secs: u64) -> bool {
|
|
191
|
+
self.get_age() > threshold_secs
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// Clear all cached data
|
|
195
|
+
pub fn clear(&mut self) -> Result<(), std::io::Error> {
|
|
196
|
+
self.data = CacheData::default();
|
|
197
|
+
self.save_to_file()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// Get cache data reference
|
|
201
|
+
pub fn data(&self) -> &CacheData {
|
|
202
|
+
&self.data
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
impl Default for Cache {
|
|
207
|
+
fn default() -> Self {
|
|
208
|
+
Self::new().unwrap_or_else(|_| Self {
|
|
209
|
+
cache_path: PathBuf::from("4runr_cache.json"),
|
|
210
|
+
data: CacheData::default(),
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/// Local data storage and caching module
|
|
2
|
-
/// Provides persistent storage for agents, runs, and system status
|
|
3
|
-
|
|
4
|
-
pub mod cache;
|
|
5
|
-
|
|
6
|
-
pub use cache::{Cache, CacheData};
|
|
1
|
+
/// Local data storage and caching module
|
|
2
|
+
/// Provides persistent storage for agents, runs, and system status
|
|
3
|
+
|
|
4
|
+
pub mod cache;
|
|
5
|
+
|
|
6
|
+
pub use cache::{Cache, CacheData};
|