4runr-os 2.9.57 → 2.9.59

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.
@@ -7,6 +7,7 @@ use ratatui::prelude::*;
7
7
  use std::time::{Duration, Instant};
8
8
 
9
9
  mod app;
10
+ mod debug_log;
10
11
  mod io;
11
12
  mod screens;
12
13
  mod storage;
@@ -600,9 +601,18 @@ fn main() -> Result<()> {
600
601
  if is_switching {
601
602
  #[cfg(debug_assertions)]
602
603
  eprintln!("[MAIN] SCREEN SWITCH: {:?} -> {:?} (clearing)", previous_screen, current_screen);
604
+ debug_log::log_screen(
605
+ &format!("{:?}", previous_screen.as_ref().unwrap_or(&current_screen)),
606
+ &format!("{:?}", current_screen),
607
+ );
603
608
  terminal.clear()?;
604
609
  }
605
610
 
611
+ // When on Setup Portal, sync terminal buffer to real console size (fixes windowed-mode corruption)
612
+ if matches!(current_screen, crate::screens::Screen::SetupPortal) {
613
+ let _ = terminal.autoresize();
614
+ }
615
+
606
616
  let render_start = Instant::now();
607
617
  terminal.draw(|f| app.render(f))?;
608
618
  let render_duration = render_start.elapsed().as_millis() as u64;
@@ -618,8 +628,12 @@ fn main() -> Result<()> {
618
628
  // OPTIMIZATION: Reduced poll timeout to 1ms for faster input detection
619
629
  // This allows loop to run ~1000 times/second when idle, but input is detected immediately
620
630
  if crossterm::event::poll(Duration::from_millis(1))? {
631
+ let on_setup = app.state.navigation.current_screen() == &screens::Screen::SetupPortal;
621
632
  match event::read()? {
622
633
  Event::Key(key) => {
634
+ if on_setup {
635
+ debug_log::log_input("Key", &format!("{:?}", key));
636
+ }
623
637
  if key.kind == KeyEventKind::Press {
624
638
  if app.handle_input(key, &mut io_handler, ws_client.as_ref())? {
625
639
  break; // Exit requested
@@ -627,8 +641,11 @@ fn main() -> Result<()> {
627
641
  }
628
642
  }
629
643
  Event::Mouse(mouse) => {
644
+ if on_setup {
645
+ debug_log::log_input("Mouse", &format!("{:?}", mouse));
646
+ }
630
647
  // Handle mouse scroll events for Setup Portal
631
- if app.state.navigation.current_screen() == &screens::Screen::SetupPortal {
648
+ if on_setup {
632
649
  if !app.state.setup_portal.detecting {
633
650
  match mouse.kind {
634
651
  MouseEventKind::ScrollUp => {
@@ -644,9 +661,11 @@ fn main() -> Result<()> {
644
661
  }
645
662
  }
646
663
  }
647
- Event::Resize(_width, _height) => {
664
+ Event::Resize(w, h) => {
665
+ if on_setup {
666
+ debug_log::log_input("Resize", &format!("{}x{}", w, h));
667
+ }
648
668
  // Terminal was resized - force immediate re-render with correct dimensions
649
- // This fixes the initial render issue where portal dimensions might be wrong
650
669
  terminal.clear()?;
651
670
  app.request_immediate_render("terminal_resize");
652
671
  }
@@ -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.57";
147
+ const PACKAGE_VERSION: &str = "2.9.59";
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)),
@@ -5,6 +5,20 @@ use ratatui::prelude::*;
5
5
  use ratatui::widgets::{Block, Borders, Paragraph, Wrap, Clear, List, ListItem};
6
6
  use crate::app::{AppState, GatewayOption};
7
7
 
8
+ /// When SETUP_PORTAL_DEBUG=1 or SETUP_PORTAL_DEBUG_FILE is set, log to file (and optionally stderr).
9
+ fn setup_debug_enabled() -> bool {
10
+ std::env::var("SETUP_PORTAL_DEBUG").as_deref() == Ok("1")
11
+ || std::env::var("SETUP_PORTAL_DEBUG_FILE").is_ok()
12
+ }
13
+
14
+ fn dbg_log(msg: &str) {
15
+ if setup_debug_enabled() {
16
+ crate::debug_log::log(msg);
17
+ #[cfg(debug_assertions)]
18
+ eprintln!("{}", msg);
19
+ }
20
+ }
21
+
8
22
  // === 4RUNR BRAND COLORS (matching layout.rs) ===
9
23
  const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
10
24
  const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
@@ -27,14 +41,22 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
27
41
 
28
42
  let area = f.size();
29
43
 
30
- // Debug: log dimensions when building with debug_assertions (cargo run / debug build)
31
- #[cfg(debug_assertions)]
32
- {
44
+ // Debug: log dimensions when SETUP_PORTAL_DEBUG=1 (release) or in debug build
45
+ let do_dbg = setup_debug_enabled() || cfg!(debug_assertions);
46
+ if do_dbg {
33
47
  static mut LAST_DIMS: Option<(u16, u16)> = None;
48
+ static mut FRAME_COUNT: u64 = 0;
49
+ static mut BANNER_SHOWN: bool = false;
34
50
  unsafe {
51
+ if !BANNER_SHOWN {
52
+ eprintln!("[SETUP_PORTAL] Debug logging active (SETUP_PORTAL_DEBUG=1 or debug build). Redirect stderr to capture, e.g. 4r 2> setup-debug.log");
53
+ BANNER_SHOWN = true;
54
+ }
55
+ FRAME_COUNT += 1;
35
56
  let changed = LAST_DIMS.map_or(true, |(w, h)| w != area.width || h != area.height);
36
- if changed {
37
- eprintln!("[SETUP_PORTAL] R#{} DIMS: {}x{} (prev: {:?})", render_id, area.width, area.height, LAST_DIMS);
57
+ if changed || FRAME_COUNT <= 15 || FRAME_COUNT % 60 == 0 {
58
+ eprintln!("[SETUP_PORTAL] R#{} frame={} DIMS: {}x{} (changed={})",
59
+ render_id, FRAME_COUNT, area.width, area.height, changed);
38
60
  LAST_DIMS = Some((area.width, area.height));
39
61
  }
40
62
  }
@@ -72,6 +94,28 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
72
94
  width: portal_width,
73
95
  height: portal_height,
74
96
  };
97
+ if do_dbg {
98
+ dbg_log(&format!("[SETUP_PORTAL] portal_area: x={} y={} w={} h={}",
99
+ portal_area.x, portal_area.y, portal_area.width, portal_area.height));
100
+ }
101
+
102
+ // File strategy: one composite RENDER line per frame (throttled) so file has full trace
103
+ if setup_debug_enabled() {
104
+ static mut RENDER_LOG_COUNT: u64 = 0;
105
+ unsafe {
106
+ RENDER_LOG_COUNT += 1;
107
+ let throttle = RENDER_LOG_COUNT <= 25 || RENDER_LOG_COUNT % 30 == 0;
108
+ if throttle {
109
+ let sel = format!("{:?}", state.setup_portal.selected_option);
110
+ crate::debug_log::log_render(&format!(
111
+ "frame={} dims={}x{} portal=({},{},{},{}) selected={}",
112
+ RENDER_LOG_COUNT, area.width, area.height,
113
+ portal_area.x, portal_area.y, portal_area.width, portal_area.height,
114
+ sel
115
+ ));
116
+ }
117
+ }
118
+ }
75
119
 
76
120
  // Split portal into sections
77
121
  use ratatui::layout::{Constraint, Direction, Layout};
@@ -99,6 +143,23 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
99
143
  .direction(Direction::Vertical)
100
144
  .constraints(constraints)
101
145
  .split(portal_area);
146
+ if do_dbg {
147
+ let c = &chunks[2];
148
+ dbg_log(&format!("[SETUP_PORTAL] content chunk: x={} y={} w={} h={}", c.x, c.y, c.width, c.height));
149
+ }
150
+ if setup_debug_enabled() {
151
+ static mut N: u64 = 0;
152
+ unsafe {
153
+ N += 1;
154
+ if N <= 25 || N % 30 == 0 {
155
+ let c = &chunks[2];
156
+ crate::debug_log::log_render(&format!(
157
+ "content_chunk=({},{},{},{})",
158
+ c.x, c.y, c.width, c.height
159
+ ));
160
+ }
161
+ }
162
+ }
102
163
 
103
164
  render_header(f, chunks[0], state);
104
165
  render_description(f, chunks[1]);
@@ -165,6 +226,18 @@ fn render_content(f: &mut Frame, area: Rect, state: &mut AppState, render_id: u6
165
226
  }
166
227
 
167
228
  fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState, _render_id: u64) {
229
+ if setup_debug_enabled() {
230
+ static mut N: u64 = 0;
231
+ unsafe {
232
+ N += 1;
233
+ if N <= 10 || N % 30 == 0 {
234
+ crate::debug_log::log_render(&format!(
235
+ "list area=({},{},{},{})",
236
+ area.x, area.y, area.width, area.height
237
+ ));
238
+ }
239
+ }
240
+ }
168
241
  // Clear this rect first so no duplicate rows from previous frame
169
242
  f.render_widget(Clear, area);
170
243
 
@@ -207,6 +280,18 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState, _render_
207
280
  .style(Style::default().bg(BG_PANEL));
208
281
 
209
282
  let inner = block.inner(area);
283
+ if setup_debug_enabled() {
284
+ static mut N: u64 = 0;
285
+ unsafe {
286
+ N += 1;
287
+ if N <= 10 || N % 30 == 0 {
288
+ crate::debug_log::log_render(&format!(
289
+ "list inner=({},{},{},{})",
290
+ inner.x, inner.y, inner.width, inner.height
291
+ ));
292
+ }
293
+ }
294
+ }
210
295
  f.render_widget(block, area);
211
296
 
212
297
  // Fill inner area
@@ -219,6 +304,18 @@ fn render_options_list(f: &mut Frame, area: Rect, state: &mut AppState, _render_
219
304
  }
220
305
 
221
306
  fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, _render_id: u64) {
307
+ if setup_debug_enabled() {
308
+ static mut N: u64 = 0;
309
+ unsafe {
310
+ N += 1;
311
+ if N <= 10 || N % 30 == 0 {
312
+ crate::debug_log::log_render(&format!(
313
+ "details area=({},{},{},{})",
314
+ area.x, area.y, area.width, area.height
315
+ ));
316
+ }
317
+ }
318
+ }
222
319
  // Clear this rect first so no leftover from previous option
223
320
  f.render_widget(Clear, area);
224
321
 
@@ -315,12 +412,27 @@ fn render_option_details(f: &mut Frame, area: Rect, state: &AppState, _render_id
315
412
  .style(Style::default().bg(BG_PANEL));
316
413
 
317
414
  let inner = block.inner(area);
415
+ if setup_debug_enabled() {
416
+ static mut N: u64 = 0;
417
+ unsafe {
418
+ N += 1;
419
+ if N <= 10 || N % 30 == 0 {
420
+ crate::debug_log::log_render(&format!(
421
+ "details inner=({},{},{},{})",
422
+ inner.x, inner.y, inner.width, inner.height
423
+ ));
424
+ }
425
+ }
426
+ }
318
427
  f.render_widget(block, area);
319
428
 
320
429
  // Validate area before rendering
321
430
  let terminal_size = f.size();
322
431
  if inner.width == 0 || inner.height == 0 ||
323
432
  inner.x >= terminal_size.width || inner.y >= terminal_size.height {
433
+ if setup_debug_enabled() {
434
+ dbg_log("[DETAILS] SKIP render: inner or terminal invalid");
435
+ }
324
436
  return;
325
437
  }
326
438
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "2.9.57",
3
+ "version": "2.9.59",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.57: Auto-update fix for Windows (shell, where 4r, better errors). v2.9.56: Setup Portal debug in debug builds. ⚠️ Pre-MVP / Development Phase",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.59: Setup Portal file debug (SETUP_PORTAL_DEBUG_FILE). v2.9.58: Autoresize + stderr debug. ⚠️ Pre-MVP / Development Phase",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",