4runr-os 2.5.0 → 2.5.2
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 +3 -0
- package/mk3-tui/src/main.rs +6 -3
- package/mk3-tui/src/screens/mod.rs +3 -0
- package/mk3-tui/src/storage/cache.rs +11 -0
- package/mk3-tui/src/storage/mod.rs +1 -1
- package/mk3-tui/src/ui/agent_builder.rs +2 -1
- package/mk3-tui/src/ui/agent_list.rs +2 -5
- package/mk3-tui/src/ui/help.rs +10 -5
- package/mk3-tui/src/ui/layout.rs +1 -1
- package/mk3-tui/src/ui/mod.rs +4 -2
- package/mk3-tui/src/ui/run_manager.rs +4 -0
- package/mk3-tui/src/websocket.rs +5 -0
- package/package.json +2 -2
package/mk3-tui/src/app.rs
CHANGED
|
@@ -682,17 +682,20 @@ impl App {
|
|
|
682
682
|
}
|
|
683
683
|
|
|
684
684
|
/// Close all overlays and popups (return to base screen)
|
|
685
|
+
#[allow(dead_code)]
|
|
685
686
|
pub fn close_all_overlays(&mut self) {
|
|
686
687
|
self.state.navigation.close_all();
|
|
687
688
|
self.request_render("close_all");
|
|
688
689
|
}
|
|
689
690
|
|
|
690
691
|
/// Get the currently visible screen
|
|
692
|
+
#[allow(dead_code)]
|
|
691
693
|
pub fn current_screen(&self) -> &Screen {
|
|
692
694
|
self.state.navigation.current_screen()
|
|
693
695
|
}
|
|
694
696
|
|
|
695
697
|
/// Check if we're on the base screen (no overlays/popups)
|
|
698
|
+
#[allow(dead_code)]
|
|
696
699
|
pub fn is_on_base_screen(&self) -> bool {
|
|
697
700
|
self.state.navigation.is_on_base()
|
|
698
701
|
}
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -187,14 +187,17 @@ fn main() -> Result<()> {
|
|
|
187
187
|
let _ = cache.update_agents(cache_agents);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
// Update agent list state
|
|
190
|
+
// Update agent list state
|
|
191
191
|
app.state.agent_list.agents = agents;
|
|
192
192
|
app.state.agent_list.selected_index = 0;
|
|
193
193
|
app.state.agent_list.detail_view = None;
|
|
194
194
|
|
|
195
|
+
// Only open AgentList overlay if we're on Main screen (not during boot)
|
|
195
196
|
use crate::screens::Screen;
|
|
196
|
-
app.
|
|
197
|
-
|
|
197
|
+
if app.state.navigation.current_screen() == &Screen::Main {
|
|
198
|
+
app.push_overlay(Screen::AgentList);
|
|
199
|
+
app.request_render("agent_list_opened");
|
|
200
|
+
}
|
|
198
201
|
}
|
|
199
202
|
} else {
|
|
200
203
|
app.add_log(format!("✓ [{}] Success", short_id));
|
|
@@ -50,6 +50,7 @@ impl Screen {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/// Returns the screen name for display
|
|
53
|
+
#[allow(dead_code)]
|
|
53
54
|
pub fn name(&self) -> &str {
|
|
54
55
|
match self {
|
|
55
56
|
Screen::Boot => "Boot",
|
|
@@ -143,12 +144,14 @@ impl NavigationState {
|
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
/// Close all overlays and popups (return to base screen)
|
|
147
|
+
#[allow(dead_code)]
|
|
146
148
|
pub fn close_all(&mut self) {
|
|
147
149
|
self.overlay_stack.clear();
|
|
148
150
|
self.popup_stack.clear();
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
/// Check if we're currently on the base screen (no overlays/popups)
|
|
154
|
+
#[allow(dead_code)]
|
|
152
155
|
pub fn is_on_base(&self) -> bool {
|
|
153
156
|
self.overlay_stack.is_empty() && self.popup_stack.is_empty()
|
|
154
157
|
}
|
|
@@ -121,6 +121,7 @@ impl Cache {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/// Add a single agent
|
|
124
|
+
#[allow(dead_code)]
|
|
124
125
|
pub fn add_agent(&mut self, agent: AgentData) -> Result<(), std::io::Error> {
|
|
125
126
|
self.data.agents.push(agent);
|
|
126
127
|
self.data.last_updated = Self::now();
|
|
@@ -128,6 +129,7 @@ impl Cache {
|
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
/// Remove an agent by name
|
|
132
|
+
#[allow(dead_code)]
|
|
131
133
|
pub fn remove_agent(&mut self, name: &str) -> Result<(), std::io::Error> {
|
|
132
134
|
self.data.agents.retain(|a| a.name != name);
|
|
133
135
|
self.data.last_updated = Self::now();
|
|
@@ -137,11 +139,13 @@ impl Cache {
|
|
|
137
139
|
// === Run Operations ===
|
|
138
140
|
|
|
139
141
|
/// Get all cached runs
|
|
142
|
+
#[allow(dead_code)]
|
|
140
143
|
pub fn get_runs(&self) -> Vec<RunData> {
|
|
141
144
|
self.data.runs.clone()
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
/// Update runs cache
|
|
148
|
+
#[allow(dead_code)]
|
|
145
149
|
pub fn update_runs(&mut self, runs: Vec<RunData>) -> Result<(), std::io::Error> {
|
|
146
150
|
self.data.runs = runs;
|
|
147
151
|
self.data.last_updated = Self::now();
|
|
@@ -149,6 +153,7 @@ impl Cache {
|
|
|
149
153
|
}
|
|
150
154
|
|
|
151
155
|
/// Add a single run
|
|
156
|
+
#[allow(dead_code)]
|
|
152
157
|
pub fn add_run(&mut self, run: RunData) -> Result<(), std::io::Error> {
|
|
153
158
|
self.data.runs.push(run);
|
|
154
159
|
self.data.last_updated = Self::now();
|
|
@@ -156,6 +161,7 @@ impl Cache {
|
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
/// Update a run by ID
|
|
164
|
+
#[allow(dead_code)]
|
|
159
165
|
pub fn update_run(&mut self, id: &str, run: RunData) -> Result<(), std::io::Error> {
|
|
160
166
|
if let Some(existing) = self.data.runs.iter_mut().find(|r| r.id == id) {
|
|
161
167
|
*existing = run;
|
|
@@ -173,6 +179,7 @@ impl Cache {
|
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
/// Update system status cache
|
|
182
|
+
#[allow(dead_code)]
|
|
176
183
|
pub fn update_system_status(&mut self, status: SystemStatusData) -> Result<(), std::io::Error> {
|
|
177
184
|
self.data.system_status = Some(status);
|
|
178
185
|
self.data.last_updated = Self::now();
|
|
@@ -182,22 +189,26 @@ impl Cache {
|
|
|
182
189
|
// === Cache Management ===
|
|
183
190
|
|
|
184
191
|
/// Get cache age in seconds
|
|
192
|
+
#[allow(dead_code)]
|
|
185
193
|
pub fn get_age(&self) -> u64 {
|
|
186
194
|
Self::now().saturating_sub(self.data.last_updated)
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
/// Check if cache is stale (older than threshold)
|
|
198
|
+
#[allow(dead_code)]
|
|
190
199
|
pub fn is_stale(&self, threshold_secs: u64) -> bool {
|
|
191
200
|
self.get_age() > threshold_secs
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
/// Clear all cached data
|
|
204
|
+
#[allow(dead_code)]
|
|
195
205
|
pub fn clear(&mut self) -> Result<(), std::io::Error> {
|
|
196
206
|
self.data = CacheData::default();
|
|
197
207
|
self.save_to_file()
|
|
198
208
|
}
|
|
199
209
|
|
|
200
210
|
/// Get cache data reference
|
|
211
|
+
#[allow(dead_code)]
|
|
201
212
|
pub fn data(&self) -> &CacheData {
|
|
202
213
|
&self.data
|
|
203
214
|
}
|
|
@@ -7,6 +7,7 @@ use crate::app::AppState;
|
|
|
7
7
|
|
|
8
8
|
// === 4RUNR BRAND COLORS (matching layout.rs) ===
|
|
9
9
|
const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
|
|
10
|
+
#[allow(dead_code)]
|
|
10
11
|
const BRAND_VIOLET: Color = Color::Rgb(148, 103, 189);
|
|
11
12
|
const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
|
|
12
13
|
const NEON_GREEN: Color = Color::Rgb(57, 255, 20);
|
|
@@ -108,7 +109,7 @@ struct CostEstimate {
|
|
|
108
109
|
is_free: bool,
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
fn calculate_cost(provider: &str, model: &str,
|
|
112
|
+
fn calculate_cost(provider: &str, model: &str, _max_tokens: u32) -> CostEstimate {
|
|
112
113
|
let pricing = get_model_pricing(provider, model);
|
|
113
114
|
let is_free = pricing.input_cost == 0.0 && pricing.output_cost == 0.0;
|
|
114
115
|
|
|
@@ -57,9 +57,8 @@ fn render_list_view(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
57
57
|
.border_style(Style::default().fg(TEXT_MUTED))
|
|
58
58
|
.style(Style::default().bg(BG_PANEL));
|
|
59
59
|
|
|
60
|
-
f.render_widget(content_block, chunks[1]);
|
|
61
|
-
|
|
62
60
|
let table_area = content_block.inner(chunks[1]);
|
|
61
|
+
f.render_widget(content_block, chunks[1]);
|
|
63
62
|
|
|
64
63
|
if state.agent_list.agents.is_empty() {
|
|
65
64
|
// Show "No agents" message
|
|
@@ -146,7 +145,6 @@ fn render_detail_popup(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
fn render_agent_detail(f: &mut Frame, area: Rect, agent: &AgentInfo) {
|
|
149
|
-
use ratatui::layout::{Constraint, Direction, Layout};
|
|
150
148
|
|
|
151
149
|
// Calculate popup size (70% width, 80% height, centered)
|
|
152
150
|
let popup_width = (area.width * 70 / 100).max(50);
|
|
@@ -181,9 +179,8 @@ fn render_agent_detail(f: &mut Frame, area: Rect, agent: &AgentInfo) {
|
|
|
181
179
|
.border_style(Style::default().fg(CYBER_CYAN))
|
|
182
180
|
.style(Style::default().bg(BG_PANEL));
|
|
183
181
|
|
|
184
|
-
f.render_widget(detail_block, popup_area);
|
|
185
|
-
|
|
186
182
|
let inner = detail_block.inner(popup_area);
|
|
183
|
+
f.render_widget(detail_block, popup_area);
|
|
187
184
|
|
|
188
185
|
// Create detail text
|
|
189
186
|
let mut detail_lines = vec![
|
package/mk3-tui/src/ui/help.rs
CHANGED
|
@@ -138,8 +138,9 @@ fn render_command_list(f: &mut Frame, area: Rect) {
|
|
|
138
138
|
|
|
139
139
|
let nav_list = List::new(nav_items);
|
|
140
140
|
|
|
141
|
+
let nav_inner = nav_block.inner(chunks[0]);
|
|
141
142
|
f.render_widget(nav_block, chunks[0]);
|
|
142
|
-
f.render_widget(nav_list,
|
|
143
|
+
f.render_widget(nav_list, nav_inner);
|
|
143
144
|
|
|
144
145
|
// Local Commands section
|
|
145
146
|
let local_block = Block::default()
|
|
@@ -158,8 +159,9 @@ fn render_command_list(f: &mut Frame, area: Rect) {
|
|
|
158
159
|
|
|
159
160
|
let local_list = List::new(local_items);
|
|
160
161
|
|
|
162
|
+
let local_inner = local_block.inner(chunks[1]);
|
|
161
163
|
f.render_widget(local_block, chunks[1]);
|
|
162
|
-
f.render_widget(local_list,
|
|
164
|
+
f.render_widget(local_list, local_inner);
|
|
163
165
|
|
|
164
166
|
// WebSocket Commands section
|
|
165
167
|
let ws_block = Block::default()
|
|
@@ -181,8 +183,9 @@ fn render_command_list(f: &mut Frame, area: Rect) {
|
|
|
181
183
|
|
|
182
184
|
let ws_list = List::new(ws_items);
|
|
183
185
|
|
|
186
|
+
let ws_inner = ws_block.inner(chunks[2]);
|
|
184
187
|
f.render_widget(ws_block, chunks[2]);
|
|
185
|
-
f.render_widget(ws_list,
|
|
188
|
+
f.render_widget(ws_list, ws_inner);
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
fn render_command_details(f: &mut Frame, area: Rect) {
|
|
@@ -242,11 +245,12 @@ fn render_command_details(f: &mut Frame, area: Rect) {
|
|
|
242
245
|
]),
|
|
243
246
|
];
|
|
244
247
|
|
|
248
|
+
let desc_inner = desc_block.inner(chunks[0]);
|
|
245
249
|
f.render_widget(desc_block, chunks[0]);
|
|
246
250
|
f.render_widget(
|
|
247
251
|
Paragraph::new(desc_text)
|
|
248
252
|
.wrap(Wrap { trim: false }),
|
|
249
|
-
|
|
253
|
+
desc_inner
|
|
250
254
|
);
|
|
251
255
|
|
|
252
256
|
// Screen controls
|
|
@@ -300,10 +304,11 @@ fn render_command_details(f: &mut Frame, area: Rect) {
|
|
|
300
304
|
]),
|
|
301
305
|
];
|
|
302
306
|
|
|
307
|
+
let controls_inner = controls_block.inner(chunks[1]);
|
|
303
308
|
f.render_widget(controls_block, chunks[1]);
|
|
304
309
|
f.render_widget(
|
|
305
310
|
Paragraph::new(controls_text)
|
|
306
311
|
.wrap(Wrap { trim: false }),
|
|
307
|
-
|
|
312
|
+
controls_inner
|
|
308
313
|
);
|
|
309
314
|
}
|
package/mk3-tui/src/ui/layout.rs
CHANGED
|
@@ -120,7 +120,7 @@ fn render_header(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
120
120
|
|
|
121
121
|
// Line 1: Brand + version + uptime - Bug 3 fix: Use "4Runr." with dot (matches brand logo)
|
|
122
122
|
// Use npm package version (2.3.5) - matches package.json
|
|
123
|
-
const PACKAGE_VERSION: &str = "2.5.
|
|
123
|
+
const PACKAGE_VERSION: &str = "2.5.2";
|
|
124
124
|
let brand_line = Line::from(vec![
|
|
125
125
|
Span::styled("4Runr.", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
|
|
126
126
|
Span::styled(" AI AGENT OS", Style::default().fg(BRAND_VIOLET)),
|
package/mk3-tui/src/ui/mod.rs
CHANGED
|
@@ -7,8 +7,10 @@ pub mod run_manager;
|
|
|
7
7
|
pub mod safe_viewport;
|
|
8
8
|
pub mod settings;
|
|
9
9
|
|
|
10
|
-
// Re-export screen states
|
|
10
|
+
// Re-export screen states (used in app.rs)
|
|
11
|
+
#[allow(dead_code)]
|
|
11
12
|
pub use agent_builder::AgentBuilderState;
|
|
13
|
+
#[allow(dead_code)]
|
|
12
14
|
pub use run_manager::RunManagerState;
|
|
15
|
+
#[allow(dead_code)]
|
|
13
16
|
pub use settings::SettingsState;
|
|
14
|
-
|
|
@@ -31,9 +31,11 @@ pub struct RunManagerState {
|
|
|
31
31
|
pub sort: RunSort,
|
|
32
32
|
|
|
33
33
|
/// Loading state
|
|
34
|
+
#[allow(dead_code)]
|
|
34
35
|
pub loading: bool,
|
|
35
36
|
|
|
36
37
|
/// Last refresh time
|
|
38
|
+
#[allow(dead_code)]
|
|
37
39
|
pub last_refresh: Option<std::time::Instant>,
|
|
38
40
|
|
|
39
41
|
/// Detailed view state (None = list view, Some(index) = detail view)
|
|
@@ -61,10 +63,12 @@ pub struct RunInfo {
|
|
|
61
63
|
|
|
62
64
|
#[derive(Debug, Clone, PartialEq)]
|
|
63
65
|
pub enum RunStatus {
|
|
66
|
+
#[allow(dead_code)]
|
|
64
67
|
Pending,
|
|
65
68
|
Running,
|
|
66
69
|
Completed,
|
|
67
70
|
Failed,
|
|
71
|
+
#[allow(dead_code)]
|
|
68
72
|
Cancelled,
|
|
69
73
|
}
|
|
70
74
|
|
package/mk3-tui/src/websocket.rs
CHANGED
|
@@ -73,11 +73,14 @@ pub enum WsClientMessage {
|
|
|
73
73
|
Event(EventMessage),
|
|
74
74
|
Error(String),
|
|
75
75
|
ConnectionLost,
|
|
76
|
+
#[allow(dead_code)]
|
|
76
77
|
Reconnecting,
|
|
78
|
+
#[allow(dead_code)]
|
|
77
79
|
ReconnectFailed(String),
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
pub struct WebSocketClient {
|
|
83
|
+
#[allow(dead_code)]
|
|
81
84
|
url: String,
|
|
82
85
|
tx: mpsc::UnboundedSender<WsMessage>,
|
|
83
86
|
rx: Arc<Mutex<mpsc::UnboundedReceiver<WsClientMessage>>>,
|
|
@@ -211,6 +214,7 @@ impl WebSocketClient {
|
|
|
211
214
|
}
|
|
212
215
|
|
|
213
216
|
/// Retry pending commands after reconnection
|
|
217
|
+
#[allow(dead_code)]
|
|
214
218
|
pub fn retry_pending_commands(&self) -> Result<Vec<String>> {
|
|
215
219
|
let mut pending = self.pending_commands.lock().unwrap();
|
|
216
220
|
let mut retried_ids = Vec::new();
|
|
@@ -239,6 +243,7 @@ impl WebSocketClient {
|
|
|
239
243
|
}
|
|
240
244
|
|
|
241
245
|
/// Clear pending commands (e.g., on explicit disconnect)
|
|
246
|
+
#[allow(dead_code)]
|
|
242
247
|
pub fn clear_pending_commands(&self) {
|
|
243
248
|
self.pending_commands.lock().unwrap().clear();
|
|
244
249
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.5.
|
|
5
|
+
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.5.2: Fixed loading screen being overshadowed by agent list during boot. Resolved all compilation warnings. Professional help popup interface, Agent List viewer with detail popup. Enhanced UX with clean navigation. Built with Rust + Ratatui. ⚠️ Pre-MVP / Development Phase",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"4runr": "dist/index.js",
|