4runr-os 2.9.49 → 2.9.51

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.
@@ -343,7 +343,7 @@ pub struct SetupPortalState {
343
343
  pub detecting: bool,
344
344
  pub detection_result: Option<DetectionResult>,
345
345
  pub error: Option<String>,
346
- pub list_state: ratatui::widgets::ListState, // CRITICAL: Must persist across frames
346
+ pub list_state: ratatui::widgets::ListState,
347
347
  }
348
348
 
349
349
  #[derive(Debug, Clone)]
@@ -382,7 +382,6 @@ impl Default for SetupPortalState {
382
382
  impl SetupPortalState {
383
383
  pub fn cycle_option(&mut self, direction: i8) {
384
384
  use GatewayOption::*;
385
- let prev = self.selected_option.clone();
386
385
  self.selected_option = match (&self.selected_option, direction) {
387
386
  // Forward cycling (Down key, Scroll Down)
388
387
  (LocalBundle, 1) => CloudServer,
@@ -402,9 +401,6 @@ impl SetupPortalState {
402
401
  CustomUrl => 2,
403
402
  };
404
403
  self.list_state.select(Some(new_index));
405
-
406
- eprintln!("[SETUP-PORTAL] cycle_option direction={} prev={:?} -> new={:?} list_index={}",
407
- direction, prev, self.selected_option, new_index);
408
404
  }
409
405
 
410
406
  pub fn reset(&mut self) {
@@ -1816,7 +1812,6 @@ impl App {
1816
1812
  // ============================================================
1817
1813
 
1818
1814
  fn handle_setup_portal_input(&mut self, key: KeyEvent, _ws_client: Option<&WebSocketClient>) -> anyhow::Result<bool> {
1819
- eprintln!("[SETUP-PORTAL] INPUT key={:?} (selected_option={:?})", key.code, self.state.setup_portal.selected_option);
1820
1815
  // Guard: Don't process if already detecting
1821
1816
  if self.state.setup_portal.detecting {
1822
1817
  return Ok(false);
@@ -1841,13 +1836,11 @@ impl App {
1841
1836
 
1842
1837
  // Up/Down - Navigate options (immediate render for responsiveness)
1843
1838
  KeyCode::Up => {
1844
- eprintln!("[SETUP-PORTAL] KEY Up -> cycle_option(-1)");
1845
1839
  self.state.setup_portal.cycle_option(-1);
1846
1840
  self.request_immediate_render("setup_nav_up");
1847
1841
  }
1848
1842
 
1849
1843
  KeyCode::Down => {
1850
- eprintln!("[SETUP-PORTAL] KEY Down -> cycle_option(1)");
1851
1844
  self.state.setup_portal.cycle_option(1);
1852
1845
  self.request_immediate_render("setup_nav_down");
1853
1846
  }
@@ -591,16 +591,13 @@ fn main() -> Result<()> {
591
591
  let current_screen = app.state.navigation.current_screen().clone();
592
592
  let is_portal_active = matches!(current_screen, crate::screens::Screen::ConnectionPortal | crate::screens::Screen::SetupPortal);
593
593
 
594
- // Clear terminal on screen switch OR if Setup Portal is active
595
- // Setup Portal needs per-frame clear to prevent terminal buffering artifacts
594
+ // Clear only on screen switch (no clear on Setup Portal nav = no flicker)
596
595
  let is_switching = match (&previous_screen, &current_screen) {
597
596
  (Some(prev), current) => prev != current,
598
- (None, _) => true, // First render
597
+ (None, _) => true,
599
598
  };
600
-
601
- let force_clear_for_setup = matches!(current_screen, crate::screens::Screen::SetupPortal);
602
-
603
- if is_switching || force_clear_for_setup {
599
+
600
+ if is_switching {
604
601
  terminal.clear()?;
605
602
  }
606
603
 
@@ -633,12 +630,10 @@ fn main() -> Result<()> {
633
630
  if !app.state.setup_portal.detecting {
634
631
  match mouse.kind {
635
632
  MouseEventKind::ScrollUp => {
636
- eprintln!("[SETUP-PORTAL] MOUSE ScrollUp -> cycle_option(-1)");
637
633
  app.state.setup_portal.cycle_option(-1);
638
634
  app.request_immediate_render("setup_portal_scroll_up");
639
635
  }
640
636
  MouseEventKind::ScrollDown => {
641
- eprintln!("[SETUP-PORTAL] MOUSE ScrollDown -> cycle_option(1)");
642
637
  app.state.setup_portal.cycle_option(1);
643
638
  app.request_immediate_render("setup_portal_scroll_down");
644
639
  }
@@ -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.49";
147
+ const PACKAGE_VERSION: &str = "2.9.51";
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,40 +18,22 @@ 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: &mut AppState) {
21
- // Per-frame render ID so we can correlate all logs from the same draw
21
+ // Per-frame render ID (used for passing to content/details; debug logs removed to avoid terminal spam)
22
22
  static mut RENDER_ID: u64 = 0;
23
23
  let render_id = unsafe {
24
24
  RENDER_ID += 1;
25
25
  RENDER_ID
26
26
  };
27
- eprintln!("[SETUP-PORTAL] R#{} START selected_option={:?}", render_id, state.setup_portal.selected_option);
28
-
29
- static mut RENDER_COUNT: u64 = 0;
30
- unsafe {
31
- RENDER_COUNT += 1;
32
- if RENDER_COUNT % 10 == 1 {
33
- eprintln!("[SETUP-PORTAL] Render #{}", RENDER_COUNT);
34
- }
35
- }
36
27
 
37
28
  let area = f.size();
38
29
 
39
- unsafe {
40
- if RENDER_COUNT % 10 == 1 {
41
- eprintln!("[SETUP-PORTAL] Terminal size: {}x{}", area.width, area.height);
42
- }
43
- }
44
-
45
30
  // CRITICAL: Validate terminal size before rendering
46
31
  // This prevents character corruption when terminal size is wrong on initial render
47
32
  if area.width == 0 || area.height == 0 {
48
- eprintln!("[SETUP-PORTAL] ⚠️ Terminal size invalid: {}x{} - skipping render", area.width, area.height);
49
33
  return;
50
34
  }
51
-
52
- // Ensure minimum size for portal (85x25)
35
+
53
36
  if area.width < 85 || area.height < 25 {
54
- eprintln!("[SETUP-PORTAL] ⚠️ Terminal too small: {}x{} (required: 85x25)", area.width, area.height);
55
37
  render_too_small(f, area);
56
38
  return;
57
39
  }
@@ -76,15 +58,7 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
76
58
  width: portal_width,
77
59
  height: portal_height,
78
60
  };
79
-
80
- // DEBUG: Log portal area calculations
81
- unsafe {
82
- if RENDER_COUNT % 10 == 1 {
83
- eprintln!("[SETUP-PORTAL] Portal area: x={}, y={}, w={}, h={}",
84
- portal_area.x, portal_area.y, portal_area.width, portal_area.height);
85
- }
86
- }
87
-
61
+
88
62
  // Split portal into sections
89
63
  use ratatui::layout::{Constraint, Direction, Layout};
90
64
 
@@ -111,31 +85,7 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
111
85
  .direction(Direction::Vertical)
112
86
  .constraints(constraints)
113
87
  .split(portal_area);
114
-
115
- // DEBUG: Log layout chunks and selected option
116
- unsafe {
117
- if RENDER_COUNT % 10 == 1 {
118
- eprintln!("[SETUP-PORTAL] Selected option: {:?}", state.setup_portal.selected_option);
119
- eprintln!("[SETUP-PORTAL] Has error: {}", has_error);
120
- eprintln!("[SETUP-PORTAL] Chunks count: {}", chunks.len());
121
- for (i, chunk) in chunks.iter().enumerate() {
122
- eprintln!("[SETUP-PORTAL] chunks[{}]: x={}, y={}, w={}, h={}",
123
- i, chunk.x, chunk.y, chunk.width, chunk.height);
124
- }
125
- // Check for overlaps
126
- for i in 0..chunks.len() {
127
- for j in (i+1)..chunks.len() {
128
- let a = &chunks[i];
129
- let b = &chunks[j];
130
- if a.x < b.x + b.width && a.x + a.width > b.x &&
131
- a.y < b.y + b.height && a.y + a.height > b.y {
132
- eprintln!("[SETUP-PORTAL] ⚠️ OVERLAP: chunks[{}] overlaps chunks[{}]!", i, j);
133
- }
134
- }
135
- }
136
- }
137
- }
138
-
88
+
139
89
  render_header(f, chunks[0], state);
140
90
  render_description(f, chunks[1]);
141
91
  render_content(f, chunks[2], state, render_id);
@@ -188,14 +138,6 @@ fn render_description(f: &mut Frame, area: Rect) {
188
138
  }
189
139
 
190
140
  fn render_content(f: &mut Frame, area: Rect, state: &mut AppState, render_id: u64) {
191
- static mut LOG_COUNT: u64 = 0;
192
- unsafe {
193
- LOG_COUNT += 1;
194
- if LOG_COUNT % 10 == 1 {
195
- eprintln!("[SETUP-PORTAL] R#{} render_content area: {}x{}", render_id, area.width, area.height);
196
- }
197
- }
198
-
199
141
  let chunks = Layout::default()
200
142
  .direction(Direction::Horizontal)
201
143
  .constraints([
@@ -223,8 +165,6 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState, render_i
223
165
  .position(|(_, opt)| opt == selected_option)
224
166
  .unwrap_or(0);
225
167
 
226
- eprintln!("[SETUP-PORTAL] R#{} LIST selected_index={} selected_option={:?}", render_id, selected_index, state.setup_portal.selected_option);
227
-
228
168
  let items: Vec<ListItem> = options
229
169
  .iter()
230
170
  .map(|(name, option)| {
@@ -257,9 +197,7 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState, render_i
257
197
  f.render_widget(list, area);
258
198
  }
259
199
 
260
- fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, render_id: u64) {
261
- eprintln!("[SETUP-PORTAL] R#{} DETAILS selected_option={:?}", render_id, state.setup_portal.selected_option);
262
-
200
+ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, _render_id: u64) {
263
201
  // CRITICAL: Fill entire area with background so every cell is overwritten.
264
202
  // Without this, Paragraph may not paint every cell; leftover shows previous option (corruption).
265
203
  let fill = Block::default().style(Style::default().bg(BG_PANEL));
@@ -350,8 +288,6 @@ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, render_id:
350
288
  ),
351
289
  };
352
290
 
353
- eprintln!("[SETUP-PORTAL] R#{} DETAILS title='{}' lines={}", render_id, title.trim(), content.len());
354
-
355
291
  // Use Block to properly contain and clear the area
356
292
  let block = Block::default()
357
293
  .title(title)
@@ -370,7 +306,6 @@ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, render_id:
370
306
  let terminal_size = f.size();
371
307
  if area.width == 0 || area.height == 0 ||
372
308
  area.x >= terminal_size.width || area.y >= terminal_size.height {
373
- eprintln!("[SETUP-PORTAL] ⚠️ ERROR: Invalid area, skipping render");
374
309
  return;
375
310
  }
376
311
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "2.9.49",
3
+ "version": "2.9.51",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.49: Setup Portal - per-frame terminal clear to fix list/details mismatch (terminal buffering). v2.9.48: Stateless list, R# debug. ⚠️ Pre-MVP / Development Phase",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.51: Setup Portal - no clear on nav (no flicker), removed debug logs. v2.9.50: Clear only when selection changed. ⚠️ Pre-MVP / Development Phase",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",