4runr-os 2.9.40 → 2.9.43

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.
@@ -144,7 +144,7 @@ fn render_header(f: &mut Frame, area: Rect, state: &AppState) {
144
144
 
145
145
  // Line 1: Brand + version + mode + uptime - Bug 3 fix: Use "4Runr." with dot (matches brand logo)
146
146
  // Use npm package version (2.9.24) - matches package.json
147
- const PACKAGE_VERSION: &str = "2.9.40";
147
+ const PACKAGE_VERSION: &str = "2.9.43";
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)),
@@ -18,18 +18,34 @@ const ERROR_RED: Color = Color::Rgb(255, 69, 69);
18
18
 
19
19
  /// Render the Setup Portal screen - Full-screen standalone portal
20
20
  pub fn render(f: &mut Frame, state: &AppState) {
21
+ // DEBUG: Track render calls
22
+ static mut RENDER_COUNT: u64 = 0;
23
+ unsafe {
24
+ RENDER_COUNT += 1;
25
+ if RENDER_COUNT % 10 == 1 { // Log every 10th render to avoid spam
26
+ eprintln!("[SETUP-PORTAL] Render #{}", RENDER_COUNT);
27
+ }
28
+ }
29
+
21
30
  let area = f.size();
22
31
 
32
+ // DEBUG: Log terminal size
33
+ unsafe {
34
+ if RENDER_COUNT % 10 == 1 {
35
+ eprintln!("[SETUP-PORTAL] Terminal size: {}x{}", area.width, area.height);
36
+ }
37
+ }
38
+
23
39
  // CRITICAL: Validate terminal size before rendering
24
40
  // This prevents character corruption when terminal size is wrong on initial render
25
41
  if area.width == 0 || area.height == 0 {
26
- // Terminal not ready - skip render
42
+ eprintln!("[SETUP-PORTAL] ⚠️ Terminal size invalid: {}x{} - skipping render", area.width, area.height);
27
43
  return;
28
44
  }
29
45
 
30
46
  // Ensure minimum size for portal (85x25)
31
47
  if area.width < 85 || area.height < 25 {
32
- // Render "too small" message
48
+ eprintln!("[SETUP-PORTAL] ⚠️ Terminal too small: {}x{} (required: 85x25)", area.width, area.height);
33
49
  render_too_small(f, area);
34
50
  return;
35
51
  }
@@ -55,6 +71,14 @@ pub fn render(f: &mut Frame, state: &AppState) {
55
71
  height: portal_height,
56
72
  };
57
73
 
74
+ // DEBUG: Log portal area calculations
75
+ unsafe {
76
+ if RENDER_COUNT % 10 == 1 {
77
+ eprintln!("[SETUP-PORTAL] Portal area: x={}, y={}, w={}, h={}",
78
+ portal_area.x, portal_area.y, portal_area.width, portal_area.height);
79
+ }
80
+ }
81
+
58
82
  // Split portal into sections
59
83
  use ratatui::layout::{Constraint, Direction, Layout};
60
84
 
@@ -82,6 +106,30 @@ pub fn render(f: &mut Frame, state: &AppState) {
82
106
  .constraints(constraints)
83
107
  .split(portal_area);
84
108
 
109
+ // DEBUG: Log layout chunks and selected option
110
+ unsafe {
111
+ if RENDER_COUNT % 10 == 1 {
112
+ eprintln!("[SETUP-PORTAL] Selected option: {:?}", state.setup_portal.selected_option);
113
+ eprintln!("[SETUP-PORTAL] Has error: {}", has_error);
114
+ eprintln!("[SETUP-PORTAL] Chunks count: {}", chunks.len());
115
+ for (i, chunk) in chunks.iter().enumerate() {
116
+ eprintln!("[SETUP-PORTAL] chunks[{}]: x={}, y={}, w={}, h={}",
117
+ i, chunk.x, chunk.y, chunk.width, chunk.height);
118
+ }
119
+ // Check for overlaps
120
+ for i in 0..chunks.len() {
121
+ for j in (i+1)..chunks.len() {
122
+ let a = &chunks[i];
123
+ let b = &chunks[j];
124
+ if a.x < b.x + b.width && a.x + a.width > b.x &&
125
+ a.y < b.y + b.height && a.y + a.height > b.y {
126
+ eprintln!("[SETUP-PORTAL] ⚠️ OVERLAP: chunks[{}] overlaps chunks[{}]!", i, j);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+
85
133
  render_header(f, chunks[0], state);
86
134
  render_description(f, chunks[1]);
87
135
  render_content(f, chunks[2], state);
@@ -134,6 +182,16 @@ fn render_description(f: &mut Frame, area: Rect) {
134
182
  }
135
183
 
136
184
  fn render_content(f: &mut Frame, area: Rect, state: &AppState) {
185
+ // DEBUG: Log content area
186
+ static mut LOG_COUNT: u64 = 0;
187
+ unsafe {
188
+ LOG_COUNT += 1;
189
+ if LOG_COUNT % 10 == 1 {
190
+ eprintln!("[SETUP-PORTAL] render_content - area: x={}, y={}, w={}, h={}",
191
+ area.x, area.y, area.width, area.height);
192
+ }
193
+ }
194
+
137
195
  // Split content into two columns: Options (left) and Details (right)
138
196
  let chunks = Layout::default()
139
197
  .direction(Direction::Horizontal)
@@ -143,11 +201,31 @@ fn render_content(f: &mut Frame, area: Rect, state: &AppState) {
143
201
  ])
144
202
  .split(area);
145
203
 
204
+ // DEBUG: Log content chunks
205
+ unsafe {
206
+ if LOG_COUNT % 10 == 1 {
207
+ eprintln!("[SETUP-PORTAL] Content chunks[0] (options): x={}, y={}, w={}, h={}",
208
+ chunks[0].x, chunks[0].y, chunks[0].width, chunks[0].height);
209
+ eprintln!("[SETUP-PORTAL] Content chunks[1] (details): x={}, y={}, w={}, h={}",
210
+ chunks[1].x, chunks[1].y, chunks[1].width, chunks[1].height);
211
+ }
212
+ }
213
+
146
214
  render_options_list(f, chunks[0], state);
147
215
  render_option_details(f, chunks[1], state);
148
216
  }
149
217
 
150
218
  fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
219
+ // DEBUG: Log options list rendering
220
+ static mut LOG_COUNT: u64 = 0;
221
+ unsafe {
222
+ LOG_COUNT += 1;
223
+ if LOG_COUNT % 10 == 1 {
224
+ eprintln!("[SETUP-PORTAL] render_options_list - area: x={}, y={}, w={}, h={}",
225
+ area.x, area.y, area.width, area.height);
226
+ }
227
+ }
228
+
151
229
  // CRITICAL: Clear the list area first to prevent duplication
152
230
  f.render_widget(Clear, area);
153
231
 
@@ -162,6 +240,15 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
162
240
  .position(|(_, opt)| opt == &state.setup_portal.selected_option)
163
241
  .unwrap_or(0);
164
242
 
243
+ // DEBUG: Log selected index
244
+ unsafe {
245
+ if LOG_COUNT % 10 == 1 {
246
+ eprintln!("[SETUP-PORTAL] Selected index: {}, option: {:?}",
247
+ selected_index, state.setup_portal.selected_option);
248
+ eprintln!("[SETUP-PORTAL] Options count: {}", options.len());
249
+ }
250
+ }
251
+
165
252
  let items: Vec<ListItem> = options
166
253
  .iter()
167
254
  .map(|(name, option)| {
@@ -203,6 +290,17 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
203
290
  }
204
291
 
205
292
  fn render_option_details(f: &mut Frame, area: Rect, state: &AppState) {
293
+ // DEBUG: Log details rendering
294
+ static mut LOG_COUNT: u64 = 0;
295
+ unsafe {
296
+ LOG_COUNT += 1;
297
+ if LOG_COUNT % 10 == 1 {
298
+ eprintln!("[SETUP-PORTAL] render_option_details - area: x={}, y={}, w={}, h={}",
299
+ area.x, area.y, area.width, area.height);
300
+ eprintln!("[SETUP-PORTAL] Selected option: {:?}", state.setup_portal.selected_option);
301
+ }
302
+ }
303
+
206
304
  // CRITICAL: Clear the details area first to prevent content overlap/corruption
207
305
  f.render_widget(Clear, area);
208
306
 
@@ -291,6 +389,18 @@ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState) {
291
389
  ),
292
390
  };
293
391
 
392
+ // DEBUG: Log what content is being rendered
393
+ unsafe {
394
+ if LOG_COUNT % 10 == 1 {
395
+ eprintln!("[SETUP-PORTAL] Title: '{}'", title);
396
+ eprintln!("[SETUP-PORTAL] Content lines: {}", content.len());
397
+ for (i, line) in content.iter().take(3).enumerate() {
398
+ let preview = format!("{:?}", line).chars().take(50).collect::<String>();
399
+ eprintln!("[SETUP-PORTAL] content[{}]: {}", i, preview);
400
+ }
401
+ }
402
+ }
403
+
294
404
  // Use Block to properly contain and clear the area
295
405
  let block = Block::default()
296
406
  .title(title)
@@ -298,15 +408,22 @@ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState) {
298
408
  .border_style(Style::default().fg(TEXT_DIM))
299
409
  .style(Style::default().bg(BG_PANEL));
300
410
 
301
- // CRITICAL: Render block first to clear and establish boundaries
302
- let inner = block.inner(area);
303
- f.render_widget(block, area);
304
-
305
- // Then render paragraph content only within the inner area
411
+ // CRITICAL: Use the standard Ratatui pattern - Paragraph with .block()
412
+ // This is more reliable than rendering Block and Paragraph separately
306
413
  let paragraph = Paragraph::new(content)
307
- .wrap(Wrap { trim: true });
414
+ .block(block)
415
+ .wrap(Wrap { trim: true })
416
+ .style(Style::default().bg(BG_PANEL)); // Ensure background fills the block
417
+
418
+ // Validate area before rendering
419
+ let terminal_size = f.size();
420
+ if area.width == 0 || area.height == 0 ||
421
+ area.x >= terminal_size.width || area.y >= terminal_size.height {
422
+ eprintln!("[SETUP-PORTAL] ⚠️ ERROR: Invalid area, skipping render");
423
+ return;
424
+ }
308
425
 
309
- f.render_widget(paragraph, inner);
426
+ f.render_widget(paragraph, area);
310
427
  }
311
428
 
312
429
  fn render_error_box(f: &mut Frame, area: Rect, state: &AppState) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "2.9.40",
3
+ "version": "2.9.43",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.40: Fixed Setup Portal rendering - added explicit Clear widgets and fixed Paragraph rendering to prevent content overlap and character corruption. v2.9.39: Fixed Setup Portal initial render bug. ⚠️ Pre-MVP / Development Phase",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.43: Release prep. v2.9.42: Reverted Setup Portal to standard Ratatui pattern - simplified rendering to fix content overlap and mixing. ⚠️ Pre-MVP / Development Phase",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",