4runr-os 2.9.45 → 2.9.46

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,6 +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
347
  }
347
348
 
348
349
  #[derive(Debug, Clone)]
@@ -366,11 +367,14 @@ pub struct CloudStatus {
366
367
 
367
368
  impl Default for SetupPortalState {
368
369
  fn default() -> Self {
370
+ let mut list_state = ratatui::widgets::ListState::default();
371
+ list_state.select(Some(0)); // Start with first option selected
369
372
  Self {
370
373
  selected_option: GatewayOption::LocalBundle,
371
374
  detecting: false,
372
375
  detection_result: None,
373
376
  error: None,
377
+ list_state,
374
378
  }
375
379
  }
376
380
  }
@@ -390,7 +394,17 @@ impl SetupPortalState {
390
394
  (CustomUrl, -1) => CloudServer,
391
395
  _ => self.selected_option.clone(),
392
396
  };
393
- eprintln!("[SETUP-PORTAL] cycle_option direction={} prev={:?} -> new={:?}", direction, prev, self.selected_option);
397
+
398
+ // CRITICAL: Update the persisted ListState index
399
+ let new_index = match self.selected_option {
400
+ LocalBundle => 0,
401
+ CloudServer => 1,
402
+ CustomUrl => 2,
403
+ };
404
+ 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);
394
408
  }
395
409
 
396
410
  pub fn reset(&mut self) {
@@ -917,7 +931,7 @@ impl App {
917
931
  }
918
932
  }
919
933
 
920
- pub fn render(&self, f: &mut Frame) {
934
+ pub fn render(&mut self, f: &mut Frame) {
921
935
  // Use new navigation system - render based on current screen
922
936
  let current = self.state.navigation.current_screen();
923
937
 
@@ -970,7 +984,7 @@ impl App {
970
984
  // Render Setup Portal as standalone screen (not overlay)
971
985
  // This eliminates double-rendering and improves performance
972
986
  use crate::ui::setup_portal;
973
- setup_portal::render(f, &self.state);
987
+ setup_portal::render(f, &mut self.state);
974
988
  }
975
989
  Screen::Confirmation { message, action } => {
976
990
  // TODO: Implement confirmation popup
@@ -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.45";
147
+ const PACKAGE_VERSION: &str = "2.9.46";
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)),
@@ -17,7 +17,7 @@ const BG_PANEL: Color = Color::Rgb(18, 18, 25);
17
17
  const ERROR_RED: Color = Color::Rgb(255, 69, 69);
18
18
 
19
19
  /// Render the Setup Portal screen - Full-screen standalone portal
20
- pub fn render(f: &mut Frame, state: &AppState) {
20
+ pub fn render(f: &mut Frame, state: &mut AppState) {
21
21
  // DEBUG: Every frame log the selection state used for this draw (no throttle)
22
22
  eprintln!("[SETUP-PORTAL] FRAME selected_option={:?}", state.setup_portal.selected_option);
23
23
 
@@ -182,7 +182,7 @@ fn render_description(f: &mut Frame, area: Rect) {
182
182
  f.render_widget(text, inner);
183
183
  }
184
184
 
185
- fn render_content(f: &mut Frame, area: Rect, state: &AppState) {
185
+ fn render_content(f: &mut Frame, area: Rect, state: &mut AppState) {
186
186
  // DEBUG: Log content area
187
187
  static mut LOG_COUNT: u64 = 0;
188
188
  unsafe {
@@ -216,7 +216,7 @@ fn render_content(f: &mut Frame, area: Rect, state: &AppState) {
216
216
  render_option_details(f, chunks[1], state);
217
217
  }
218
218
 
219
- fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
219
+ fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState) {
220
220
  // DEBUG: Log options list rendering
221
221
  static mut LOG_COUNT: u64 = 0;
222
222
  unsafe {
@@ -274,9 +274,11 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
274
274
  })
275
275
  .collect();
276
276
 
277
- // Create ListState with selected index
278
- let mut list_state = ListState::default();
279
- list_state.select(Some(selected_index));
277
+ // CRITICAL: Use the PERSISTED ListState from app state (not a new one each frame)
278
+ // This is required for Ratatui's stateful widget to maintain selection across frames
279
+ let list_state_selected = state.setup_portal.list_state.selected();
280
+ eprintln!("[SETUP-PORTAL] LIST About to render: list_state.selected()={:?} selected_index={} selected_option={:?}",
281
+ list_state_selected, selected_index, state.setup_portal.selected_option);
280
282
 
281
283
  // Use Block to properly contain and clear the area
282
284
  let block = Block::default()
@@ -289,7 +291,8 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &AppState) {
289
291
  .block(block)
290
292
  .highlight_style(Style::default().fg(CYBER_CYAN).bold().bg(BG_PANEL));
291
293
 
292
- f.render_stateful_widget(list, area, &mut list_state);
294
+ // CRITICAL: Pass the mutable reference to the persisted ListState
295
+ f.render_stateful_widget(list, area, &mut state.setup_portal.list_state);
293
296
  }
294
297
 
295
298
  fn render_option_details(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.45",
3
+ "version": "2.9.46",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.45: Setup Portal debug logging for navigation (input/state/frame). v2.9.44: Setup Portal fill-background fix for duplication and corruption. ⚠️ Pre-MVP / Development Phase",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.46: Setup Portal navigation fix - persisted ListState so selection matches visual. v2.9.45: Debug logging. v2.9.44: Fill-background fix. ⚠️ Pre-MVP / Development Phase",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",