4runr-os 2.3.5 → 2.3.8
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/ui/boot.rs +41 -27
- package/mk3-tui/src/ui/layout.rs +1 -1
- package/package.json +1 -1
package/mk3-tui/src/ui/boot.rs
CHANGED
|
@@ -2,13 +2,17 @@ use crate::app::AppState;
|
|
|
2
2
|
use ratatui::prelude::*;
|
|
3
3
|
use ratatui::widgets::{Block, Borders, Gauge, Paragraph};
|
|
4
4
|
|
|
5
|
-
// Color constants matching the TUI palette
|
|
5
|
+
// Color constants matching the TUI palette (exact match from layout.rs)
|
|
6
6
|
const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
|
|
7
|
+
#[allow(dead_code)]
|
|
8
|
+
const BRAND_VIOLET: Color = Color::Rgb(148, 103, 189);
|
|
7
9
|
const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
|
|
8
10
|
const NEON_GREEN: Color = Color::Rgb(57, 255, 20);
|
|
11
|
+
const TEXT_PRIMARY: Color = Color::Rgb(230, 230, 240);
|
|
9
12
|
const TEXT_DIM: Color = Color::Rgb(100, 100, 120);
|
|
10
|
-
|
|
11
|
-
const
|
|
13
|
+
#[allow(dead_code)]
|
|
14
|
+
const TEXT_MUTED: Color = Color::Rgb(60, 60, 80);
|
|
15
|
+
const BG_PANEL: Color = Color::Rgb(18, 18, 25);
|
|
12
16
|
|
|
13
17
|
/// Exact logo from requirements (monospace, preserve spacing)
|
|
14
18
|
const LOGO: &str = r#"██╗ ██╗██████╗ ██╗ ██╗███╗ ██╗██████╗ ██████╗ ███████╗
|
|
@@ -21,49 +25,55 @@ const LOGO: &str = r#"██╗ ██╗██████╗ ██╗ █
|
|
|
21
25
|
pub fn render_boot(f: &mut Frame, area: Rect, state: &AppState) {
|
|
22
26
|
// Clear background
|
|
23
27
|
f.render_widget(
|
|
24
|
-
Block::default().style(Style::default().bg(
|
|
28
|
+
Block::default().style(Style::default().bg(BG_PANEL)),
|
|
25
29
|
area,
|
|
26
30
|
);
|
|
27
31
|
|
|
28
|
-
//
|
|
29
|
-
let logo_height = 6; // Logo is 6 lines
|
|
30
|
-
let boot_logs_height =
|
|
31
|
-
let progress_height = 3;
|
|
32
|
-
let footer_height = 1;
|
|
32
|
+
// Fixed layout: logo stays at fixed position, elements below it
|
|
33
|
+
let logo_height: u16 = 6; // Logo is 6 lines
|
|
34
|
+
let boot_logs_height: u16 = 5; // Fixed height for logs (not dynamic)
|
|
35
|
+
let progress_height: u16 = 3;
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
let
|
|
37
|
+
// Logo starts at a fixed position from top (about 1/4 down the screen)
|
|
38
|
+
let logo_start_y: u16 = area.height / 4;
|
|
36
39
|
|
|
37
|
-
// === LOGO (centered horizontally) ===
|
|
40
|
+
// === LOGO (centered horizontally, fixed vertical position) ===
|
|
38
41
|
let logo_lines: Vec<&str> = LOGO.lines().collect();
|
|
39
|
-
let logo_width = logo_lines.iter().map(|l| l.len()).max().unwrap_or(0) as u16;
|
|
40
|
-
|
|
42
|
+
let logo_width: u16 = logo_lines.iter().map(|l| l.len()).max().unwrap_or(0) as u16;
|
|
43
|
+
// Center horizontally: (area.width - logo_width) / 2
|
|
44
|
+
let logo_x: u16 = area.x + (area.width.saturating_sub(logo_width)) / 2;
|
|
41
45
|
|
|
42
46
|
for (i, line) in logo_lines.iter().enumerate() {
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
let line_y = logo_start_y + i as u16;
|
|
48
|
+
if line_y < area.height {
|
|
49
|
+
// Center each line within the available width
|
|
50
|
+
let line_rect = Rect {
|
|
45
51
|
x: logo_x,
|
|
46
|
-
y:
|
|
52
|
+
y: line_y,
|
|
47
53
|
width: logo_width.min(area.width.saturating_sub(logo_x)),
|
|
48
54
|
height: 1,
|
|
49
55
|
};
|
|
50
56
|
f.render_widget(
|
|
51
57
|
Paragraph::new(*line)
|
|
52
58
|
.style(Style::default().fg(BRAND_PURPLE))
|
|
53
|
-
.alignment(Alignment::
|
|
54
|
-
|
|
59
|
+
.alignment(Alignment::Center), // Center alignment for perfect centering
|
|
60
|
+
line_rect,
|
|
55
61
|
);
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
let current_y =
|
|
65
|
+
let current_y = logo_start_y + logo_height + 2;
|
|
60
66
|
|
|
61
67
|
// === BOOT LOGS ===
|
|
62
68
|
if !state.boot_lines.is_empty() && current_y < area.height {
|
|
69
|
+
// Center logs horizontally
|
|
70
|
+
let logs_width: u16 = (area.width * 60 / 100).min(area.width.saturating_sub(40)); // 60% width, safe margins
|
|
71
|
+
let logs_x: u16 = area.x + (area.width.saturating_sub(logs_width)) / 2;
|
|
72
|
+
|
|
63
73
|
let logs_area = Rect {
|
|
64
|
-
x:
|
|
74
|
+
x: logs_x,
|
|
65
75
|
y: current_y,
|
|
66
|
-
width:
|
|
76
|
+
width: logs_width,
|
|
67
77
|
height: boot_logs_height,
|
|
68
78
|
};
|
|
69
79
|
|
|
@@ -76,7 +86,7 @@ pub fn render_boot(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
76
86
|
f.render_widget(
|
|
77
87
|
Paragraph::new(log_text.trim())
|
|
78
88
|
.style(Style::default().fg(TEXT_PRIMARY))
|
|
79
|
-
.alignment(Alignment::
|
|
89
|
+
.alignment(Alignment::Center), // Center logs too
|
|
80
90
|
logs_area,
|
|
81
91
|
);
|
|
82
92
|
}
|
|
@@ -85,10 +95,14 @@ pub fn render_boot(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
85
95
|
|
|
86
96
|
// === PROGRESS BAR ===
|
|
87
97
|
if current_y < area.height {
|
|
98
|
+
// Center progress bar horizontally
|
|
99
|
+
let progress_width: u16 = (area.width * 60 / 100).min(area.width.saturating_sub(40));
|
|
100
|
+
let progress_x: u16 = area.x + (area.width.saturating_sub(progress_width)) / 2;
|
|
101
|
+
|
|
88
102
|
let progress_area = Rect {
|
|
89
|
-
x:
|
|
103
|
+
x: progress_x,
|
|
90
104
|
y: current_y,
|
|
91
|
-
width:
|
|
105
|
+
width: progress_width,
|
|
92
106
|
height: 3,
|
|
93
107
|
};
|
|
94
108
|
|
|
@@ -118,9 +132,9 @@ pub fn render_boot(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
118
132
|
// === FOOTER: "Press any key to continue" (only when boot done) ===
|
|
119
133
|
if state.boot_done && current_y < area.height {
|
|
120
134
|
let footer_area = Rect {
|
|
121
|
-
x: area.x
|
|
135
|
+
x: area.x,
|
|
122
136
|
y: current_y,
|
|
123
|
-
width:
|
|
137
|
+
width: area.width,
|
|
124
138
|
height: footer_height,
|
|
125
139
|
};
|
|
126
140
|
|
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.3.
|
|
123
|
+
const PACKAGE_VERSION: &str = "2.3.8";
|
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.3.5: Fixed boot screen logo rendering (restored original working version), fully functional Agent Builder with input handling and TUI styling. Built with Rust + Ratatui. ⚠️ Pre-MVP / Development Phase",
|
|
6
6
|
"main": "dist/index.js",
|