4runr-os 2.9.16 → 2.9.17
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/binaries/win32-x64/mk3-tui.exe +0 -0
- package/mk3-tui/src/app.rs +14 -10
- package/mk3-tui/src/main.rs +27 -2
- package/mk3-tui/src/screens/mod.rs +3 -3
- package/mk3-tui/src/ui/connection_portal.rs +8 -9
- package/mk3-tui/src/ui/layout.rs +2 -2
- package/mk3-tui/src/ui/setup_portal.rs +7 -8
- package/package.json +2 -2
|
Binary file
|
package/mk3-tui/src/app.rs
CHANGED
|
@@ -721,12 +721,15 @@ impl App {
|
|
|
721
721
|
}
|
|
722
722
|
}
|
|
723
723
|
"connect portal" | "portal" => {
|
|
724
|
-
|
|
724
|
+
// Navigate to portal as base screen (standalone, not overlay)
|
|
725
|
+
self.state.navigation.navigate_to_base(Screen::ConnectionPortal);
|
|
725
726
|
self.state.connection_portal.reset();
|
|
726
727
|
self.state.logs.push_back("[NAV] Opening Connection Portal...".into());
|
|
728
|
+
self.request_render("open_connection_portal");
|
|
727
729
|
}
|
|
728
730
|
"setup" | "setup gateway" | "setup portal" => {
|
|
729
|
-
|
|
731
|
+
// Navigate to portal as base screen (standalone, not overlay)
|
|
732
|
+
self.state.navigation.navigate_to_base(Screen::SetupPortal);
|
|
730
733
|
self.state.setup_portal.reset();
|
|
731
734
|
|
|
732
735
|
// Auto-detect Gateway options when portal opens
|
|
@@ -1651,9 +1654,10 @@ impl App {
|
|
|
1651
1654
|
}
|
|
1652
1655
|
|
|
1653
1656
|
match key.code {
|
|
1654
|
-
// ESC - Close portal
|
|
1657
|
+
// ESC - Close portal and return to Main
|
|
1655
1658
|
KeyCode::Esc => {
|
|
1656
|
-
|
|
1659
|
+
// Navigate back to Main (portals are now base screens, not overlays)
|
|
1660
|
+
self.state.navigation.navigate_to_base(Screen::Main);
|
|
1657
1661
|
self.add_log("[NAV] Connection Portal closed".to_string());
|
|
1658
1662
|
self.request_render("portal_close");
|
|
1659
1663
|
}
|
|
@@ -1770,15 +1774,16 @@ impl App {
|
|
|
1770
1774
|
match key.code {
|
|
1771
1775
|
// ESC - Cancel and close portal
|
|
1772
1776
|
KeyCode::Esc => {
|
|
1773
|
-
|
|
1777
|
+
// Navigate back to Main (portals are now base screens, not overlays)
|
|
1778
|
+
self.state.navigation.navigate_to_base(Screen::Main);
|
|
1774
1779
|
self.add_log("[NAV] Setup Portal closed".to_string());
|
|
1775
1780
|
self.request_render("setup_portal_close");
|
|
1776
1781
|
}
|
|
1777
1782
|
|
|
1778
1783
|
// F2 - Go directly to Connection Portal
|
|
1779
1784
|
KeyCode::F(2) => {
|
|
1780
|
-
|
|
1781
|
-
self.
|
|
1785
|
+
// Navigate to portal as base screen (standalone, not overlay)
|
|
1786
|
+
self.state.navigation.navigate_to_base(Screen::ConnectionPortal);
|
|
1782
1787
|
self.add_log("[NAV] Opening Connection Portal...".to_string());
|
|
1783
1788
|
self.request_render("open_connection_portal");
|
|
1784
1789
|
}
|
|
@@ -1814,9 +1819,8 @@ impl App {
|
|
|
1814
1819
|
self.state.connection_portal.error = None;
|
|
1815
1820
|
self.state.connection_portal.connection_success = false;
|
|
1816
1821
|
|
|
1817
|
-
// Navigate to Connection Portal
|
|
1818
|
-
self.
|
|
1819
|
-
self.push_overlay(Screen::ConnectionPortal);
|
|
1822
|
+
// Navigate to Connection Portal as base screen (standalone, not overlay)
|
|
1823
|
+
self.state.navigation.navigate_to_base(Screen::ConnectionPortal);
|
|
1820
1824
|
|
|
1821
1825
|
self.add_log(format!("[SETUP] Selected {} - Opening Connection Portal",
|
|
1822
1826
|
self.state.setup_portal.selected_option.as_str()));
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -70,6 +70,9 @@ fn main() -> Result<()> {
|
|
|
70
70
|
let start_time = Instant::now();
|
|
71
71
|
let mut last_tick = Instant::now();
|
|
72
72
|
|
|
73
|
+
// Track previous screen to detect portal navigation
|
|
74
|
+
let mut previous_screen: Option<crate::screens::Screen> = None;
|
|
75
|
+
|
|
73
76
|
// Force initial render
|
|
74
77
|
app.request_render("initial");
|
|
75
78
|
|
|
@@ -378,8 +381,9 @@ fn main() -> Result<()> {
|
|
|
378
381
|
// Bundle is running! Proceed to Connection Portal
|
|
379
382
|
app.add_log(format!("✓ [{}] Local Bundle detected and running", short_id));
|
|
380
383
|
app.state.connection_portal.gateway_url = "http://localhost:3001".to_string();
|
|
381
|
-
|
|
382
|
-
app.
|
|
384
|
+
// Navigate to portal as base screen (standalone, not overlay)
|
|
385
|
+
app.state.navigation.navigate_to_base(crate::screens::Screen::ConnectionPortal);
|
|
386
|
+
app.request_render("setup_detect_success");
|
|
383
387
|
} else if exists {
|
|
384
388
|
// Bundle exists but not running
|
|
385
389
|
app.add_log(format!("⚠ [{}] Local Bundle found but not running", short_id));
|
|
@@ -513,10 +517,31 @@ fn main() -> Result<()> {
|
|
|
513
517
|
// Check if render is scheduled and throttle limit has passed
|
|
514
518
|
// OPTIMIZATION: Removed input debounce check - using immediate render for typing
|
|
515
519
|
if app.should_render() {
|
|
520
|
+
// Check if we're switching to a portal - clear terminal buffer for clean transition
|
|
521
|
+
// Clone current screen before mutable borrow
|
|
522
|
+
let current_screen = app.state.navigation.current_screen().clone();
|
|
523
|
+
let is_switching_to_portal = match (&previous_screen, ¤t_screen) {
|
|
524
|
+
(Some(prev), current) if prev != current => {
|
|
525
|
+
matches!(current, crate::screens::Screen::ConnectionPortal | crate::screens::Screen::SetupPortal)
|
|
526
|
+
}
|
|
527
|
+
(None, current) => {
|
|
528
|
+
matches!(current, crate::screens::Screen::ConnectionPortal | crate::screens::Screen::SetupPortal)
|
|
529
|
+
}
|
|
530
|
+
_ => false,
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
if is_switching_to_portal {
|
|
534
|
+
// Clear terminal buffer when switching to portal for clean standalone rendering
|
|
535
|
+
terminal.clear()?;
|
|
536
|
+
}
|
|
537
|
+
|
|
516
538
|
let render_start = Instant::now();
|
|
517
539
|
terminal.draw(|f| app.render(f))?;
|
|
518
540
|
let render_duration = render_start.elapsed().as_millis() as u64;
|
|
519
541
|
app.record_render(render_duration);
|
|
542
|
+
|
|
543
|
+
// Update previous screen tracking
|
|
544
|
+
previous_screen = Some(current_screen);
|
|
520
545
|
}
|
|
521
546
|
|
|
522
547
|
// ┌─────────────────────────────────────────────────────────┐
|
|
@@ -33,7 +33,7 @@ impl Screen {
|
|
|
33
33
|
pub fn is_overlay(&self) -> bool {
|
|
34
34
|
matches!(
|
|
35
35
|
self,
|
|
36
|
-
Screen::AgentBuilder | Screen::RunManager | Screen::Settings | Screen::AgentList
|
|
36
|
+
Screen::AgentBuilder | Screen::RunManager | Screen::Settings | Screen::AgentList
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -45,9 +45,9 @@ impl Screen {
|
|
|
45
45
|
)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/// Returns true if this screen is a base screen
|
|
48
|
+
/// Returns true if this screen is a base screen (full-screen standalone)
|
|
49
49
|
pub fn is_base(&self) -> bool {
|
|
50
|
-
matches!(self, Screen::Boot | Screen::Main)
|
|
50
|
+
matches!(self, Screen::Boot | Screen::Main | Screen::ConnectionPortal | Screen::SetupPortal)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/// Returns the screen name for display
|
|
@@ -17,20 +17,19 @@ const TEXT_MUTED: Color = Color::Rgb(60, 60, 80);
|
|
|
17
17
|
const BG_PANEL: Color = Color::Rgb(18, 18, 25);
|
|
18
18
|
const ERROR_RED: Color = Color::Rgb(255, 69, 69);
|
|
19
19
|
|
|
20
|
-
/// Main render function
|
|
20
|
+
/// Main render function - Full-screen standalone portal
|
|
21
21
|
pub fn render(f: &mut Frame, state: &AppState) {
|
|
22
22
|
let area = f.size();
|
|
23
23
|
|
|
24
|
-
// CRITICAL
|
|
24
|
+
// CRITICAL: Clear the ENTIRE screen first - this is a standalone screen, not an overlay
|
|
25
25
|
f.render_widget(Clear, area);
|
|
26
26
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
f.render_widget(overlay, area);
|
|
27
|
+
// Render full-screen background (no dimming - this is the only screen)
|
|
28
|
+
let bg = Block::default()
|
|
29
|
+
.style(Style::default().bg(BG_PANEL));
|
|
30
|
+
f.render_widget(bg, area);
|
|
32
31
|
|
|
33
|
-
// Calculate centered portal dimensions
|
|
32
|
+
// Calculate centered portal dimensions (smaller dialog on full-screen background)
|
|
34
33
|
let portal_width = area.width.min(80).max(60);
|
|
35
34
|
let portal_height = area.height.min(28).max(22);
|
|
36
35
|
|
|
@@ -44,7 +43,7 @@ pub fn render(f: &mut Frame, state: &AppState) {
|
|
|
44
43
|
height: portal_height,
|
|
45
44
|
};
|
|
46
45
|
|
|
47
|
-
// Clear the portal area
|
|
46
|
+
// Clear the portal area for clean rendering
|
|
48
47
|
f.render_widget(Clear, portal_area);
|
|
49
48
|
|
|
50
49
|
// Render portal background
|
package/mk3-tui/src/ui/layout.rs
CHANGED
|
@@ -143,8 +143,8 @@ fn render_header(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
143
143
|
};
|
|
144
144
|
|
|
145
145
|
// Line 1: Brand + version + mode + uptime - Bug 3 fix: Use "4Runr." with dot (matches brand logo)
|
|
146
|
-
// Use npm package version (2.9.
|
|
147
|
-
const PACKAGE_VERSION: &str = "2.9.
|
|
146
|
+
// Use npm package version (2.9.17) - matches package.json
|
|
147
|
+
const PACKAGE_VERSION: &str = "2.9.17";
|
|
148
148
|
let brand_line = Line::from(vec![
|
|
149
149
|
Span::styled("4Runr.", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
|
|
150
150
|
Span::styled(" AI AGENT OS", Style::default().fg(BRAND_VIOLET)),
|
|
@@ -16,18 +16,17 @@ const TEXT_MUTED: Color = Color::Rgb(60, 60, 80);
|
|
|
16
16
|
const BG_PANEL: Color = Color::Rgb(18, 18, 25);
|
|
17
17
|
const ERROR_RED: Color = Color::Rgb(255, 69, 69);
|
|
18
18
|
|
|
19
|
-
/// Render the Setup Portal screen
|
|
19
|
+
/// Render the Setup Portal screen - Full-screen standalone portal
|
|
20
20
|
pub fn render(f: &mut Frame, state: &AppState) {
|
|
21
21
|
let area = f.size();
|
|
22
22
|
|
|
23
|
-
// CRITICAL
|
|
23
|
+
// CRITICAL: Clear the ENTIRE screen first - this is a standalone screen, not an overlay
|
|
24
24
|
f.render_widget(Clear, area);
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
f.render_widget(overlay, area);
|
|
26
|
+
// Render full-screen background (no dimming - this is the only screen)
|
|
27
|
+
let bg = Block::default()
|
|
28
|
+
.style(Style::default().bg(BG_PANEL));
|
|
29
|
+
f.render_widget(bg, area);
|
|
31
30
|
|
|
32
31
|
// Center the portal dialog - larger for better visibility
|
|
33
32
|
let portal_width = area.width.min(110).max(85);
|
|
@@ -42,7 +41,7 @@ pub fn render(f: &mut Frame, state: &AppState) {
|
|
|
42
41
|
height: portal_height,
|
|
43
42
|
};
|
|
44
43
|
|
|
45
|
-
// Clear the portal area
|
|
44
|
+
// Clear the portal area for clean rendering
|
|
46
45
|
f.render_widget(Clear, portal_area);
|
|
47
46
|
|
|
48
47
|
// Split portal into sections
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.17",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.16: Portal complete isolation (pauses base screen state updates). v2.9.14: Portal standalone rendering.
|
|
5
|
+
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.17: Portals are now standalone base screens (not overlays) - complete isolation, no background OS, terminal cleared on switch. v2.9.16: Portal complete isolation (pauses base screen state updates). v2.9.14: Portal standalone rendering. ⚠️ Pre-MVP / Development Phase",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"4runr": "dist/index.js",
|