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.
@@ -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
- const TEXT_PRIMARY: Color = Color::Rgb(220, 220, 240);
11
- const BG_DARK: Color = Color::Rgb(10, 10, 15);
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(BG_DARK)),
28
+ Block::default().style(Style::default().bg(BG_PANEL)),
25
29
  area,
26
30
  );
27
31
 
28
- // Calculate layout: logo on top half, boot logs below, progress bar, footer
29
- let logo_height = 6; // Logo is 6 lines
30
- let boot_logs_height = state.boot_lines.len().min(10) as u16; // Max 10 lines visible
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
- let total_content_height = logo_height + 2 + boot_logs_height + 2 + progress_height + 2 + footer_height;
35
- let start_y = (area.height.saturating_sub(total_content_height)) / 2;
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
- let logo_x = (area.width.saturating_sub(logo_width)) / 2;
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
- if start_y + i as u16 < area.height {
44
- let logo_rect = Rect {
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: start_y + i as u16,
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::Left),
54
- logo_rect,
59
+ .alignment(Alignment::Center), // Center alignment for perfect centering
60
+ line_rect,
55
61
  );
56
62
  }
57
63
  }
58
64
 
59
- let current_y = start_y + logo_height + 2;
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: area.x + (area.width * 10 / 100), // 10% margin from left
74
+ x: logs_x,
65
75
  y: current_y,
66
- width: (area.width * 80 / 100).min(area.width.saturating_sub(20)), // 80% width, safe from right edge
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::Left),
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: area.x + (area.width * 10 / 100),
103
+ x: progress_x,
90
104
  y: current_y,
91
- width: (area.width * 80 / 100).min(area.width.saturating_sub(20)),
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 + (area.width * 10 / 100),
135
+ x: area.x,
122
136
  y: current_y,
123
- width: (area.width * 80 / 100).min(area.width.saturating_sub(20)),
137
+ width: area.width,
124
138
  height: footer_height,
125
139
  };
126
140
 
@@ -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.5";
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.5",
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",