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.
|
Binary file
|
package/mk3-tui/src/app.rs
CHANGED
|
@@ -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,
|
|
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
|
}
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -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
|
|
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, ¤t_screen) {
|
|
597
596
|
(Some(prev), current) => prev != current,
|
|
598
|
-
(None, _) => true,
|
|
597
|
+
(None, _) => true,
|
|
599
598
|
};
|
|
600
|
-
|
|
601
|
-
|
|
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
|
}
|
package/mk3-tui/src/ui/layout.rs
CHANGED
|
@@ -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.
|
|
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
|
|
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,
|
|
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.
|
|
3
|
+
"version": "2.9.51",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.9.
|
|
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",
|