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.
@@ -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
- // WebSocket Commands - Label BEFORE commands with clear separator
387
- self.state.logs.push_back("[HELP] ─────────────────────────────────────────".into());
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
  }
@@ -172,11 +172,14 @@ fn main() -> Result<()> {
172
172
  let _ = cache.update_agents(agents);
173
173
  }
174
174
 
175
- app.add_log(format!(
176
- "✓ [{}] Loaded {} agents",
177
- short_id,
178
- agents_array.len()
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};