4runr-os 2.9.72 → 2.9.73
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.
- package/mk3-tui/src/app.rs +9 -0
- package/mk3-tui/src/main.rs +24 -2
- package/package.json +2 -2
package/mk3-tui/src/app.rs
CHANGED
|
@@ -341,6 +341,8 @@ impl GatewayOption {
|
|
|
341
341
|
pub struct SetupPortalState {
|
|
342
342
|
pub selected_option: GatewayOption,
|
|
343
343
|
pub detecting: bool,
|
|
344
|
+
/// When detection started (for timeout so portal never stays frozen)
|
|
345
|
+
pub detecting_since: Option<std::time::Instant>,
|
|
344
346
|
pub detection_result: Option<DetectionResult>,
|
|
345
347
|
pub error: Option<String>,
|
|
346
348
|
pub list_state: ratatui::widgets::ListState,
|
|
@@ -372,6 +374,7 @@ impl Default for SetupPortalState {
|
|
|
372
374
|
Self {
|
|
373
375
|
selected_option: GatewayOption::LocalBundle,
|
|
374
376
|
detecting: false,
|
|
377
|
+
detecting_since: None,
|
|
375
378
|
detection_result: None,
|
|
376
379
|
error: None,
|
|
377
380
|
list_state,
|
|
@@ -405,6 +408,7 @@ impl SetupPortalState {
|
|
|
405
408
|
|
|
406
409
|
pub fn reset(&mut self) {
|
|
407
410
|
self.detecting = false;
|
|
411
|
+
self.detecting_since = None;
|
|
408
412
|
self.detection_result = None;
|
|
409
413
|
self.error = None;
|
|
410
414
|
}
|
|
@@ -647,11 +651,13 @@ impl App {
|
|
|
647
651
|
self.state.setup_portal.reset();
|
|
648
652
|
if let Some(ws) = ws_client {
|
|
649
653
|
self.state.setup_portal.detecting = true;
|
|
654
|
+
self.state.setup_portal.detecting_since = Some(std::time::Instant::now());
|
|
650
655
|
if let Ok(id) = ws.send_command("setup.detect", None) {
|
|
651
656
|
self.state.pending_setup_detect_id = Some(id);
|
|
652
657
|
self.add_log("[SETUP] Detecting Gateway options...".to_string());
|
|
653
658
|
} else {
|
|
654
659
|
self.state.setup_portal.detecting = false;
|
|
660
|
+
self.state.setup_portal.detecting_since = None;
|
|
655
661
|
self.state.setup_portal.error = Some("Failed to start detection".to_string());
|
|
656
662
|
}
|
|
657
663
|
}
|
|
@@ -796,11 +802,13 @@ impl App {
|
|
|
796
802
|
// Auto-detect Gateway options when portal opens
|
|
797
803
|
if let Some(ws) = ws_client {
|
|
798
804
|
self.state.setup_portal.detecting = true;
|
|
805
|
+
self.state.setup_portal.detecting_since = Some(std::time::Instant::now());
|
|
799
806
|
if let Ok(id) = ws.send_command("setup.detect", None) {
|
|
800
807
|
self.state.pending_setup_detect_id = Some(id);
|
|
801
808
|
self.add_log("[SETUP] Detecting Gateway options...".to_string());
|
|
802
809
|
} else {
|
|
803
810
|
self.state.setup_portal.detecting = false;
|
|
811
|
+
self.state.setup_portal.detecting_since = None;
|
|
804
812
|
self.state.setup_portal.error = Some("Failed to start detection".to_string());
|
|
805
813
|
}
|
|
806
814
|
}
|
|
@@ -1832,6 +1840,7 @@ impl App {
|
|
|
1832
1840
|
// ESC always closes the portal (even when detecting), so user can always get out
|
|
1833
1841
|
if key.code == KeyCode::Esc {
|
|
1834
1842
|
self.state.setup_portal.detecting = false;
|
|
1843
|
+
self.state.setup_portal.detecting_since = None;
|
|
1835
1844
|
self.state.navigation.navigate_to_base(Screen::Main);
|
|
1836
1845
|
self.add_log("[NAV] Setup Portal closed".to_string());
|
|
1837
1846
|
self.request_immediate_render("setup_portal_close");
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use anyhow::Result;
|
|
2
2
|
use crossterm::cursor;
|
|
3
|
-
use crossterm::event::{self, Event, KeyEventKind, MouseEventKind};
|
|
3
|
+
use crossterm::event::{self, Event, KeyCode, KeyEventKind, MouseEventKind};
|
|
4
4
|
use crossterm::execute;
|
|
5
5
|
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, Clear, ClearType};
|
|
6
6
|
use ratatui::prelude::*;
|
|
@@ -370,6 +370,7 @@ fn main() -> Result<()> {
|
|
|
370
370
|
if Some(&resp.id) == app.state.pending_setup_detect_id.as_ref() {
|
|
371
371
|
app.state.pending_setup_detect_id = None;
|
|
372
372
|
app.state.setup_portal.detecting = false;
|
|
373
|
+
app.state.setup_portal.detecting_since = None;
|
|
373
374
|
|
|
374
375
|
use crate::app::{DetectionResult, BundleStatus, CloudStatus};
|
|
375
376
|
|
|
@@ -404,6 +405,7 @@ fn main() -> Result<()> {
|
|
|
404
405
|
let running = obj.get("running").and_then(|v| v.as_bool()).unwrap_or(false);
|
|
405
406
|
|
|
406
407
|
app.state.setup_portal.detecting = false;
|
|
408
|
+
app.state.setup_portal.detecting_since = None;
|
|
407
409
|
// Note: We don't update detection_result here anymore
|
|
408
410
|
// The new system uses setup.detect for comprehensive detection
|
|
409
411
|
|
|
@@ -524,6 +526,7 @@ fn main() -> Result<()> {
|
|
|
524
526
|
else if Some(&resp.id) == app.state.pending_setup_detect_id.as_ref() {
|
|
525
527
|
app.state.pending_setup_detect_id = None;
|
|
526
528
|
app.state.setup_portal.detecting = false;
|
|
529
|
+
app.state.setup_portal.detecting_since = None;
|
|
527
530
|
app.state.setup_portal.error = Some(error_msg.clone());
|
|
528
531
|
app.add_log(format!("✗ [{}] Setup detection failed: {}", short_id, error_msg));
|
|
529
532
|
}
|
|
@@ -531,6 +534,7 @@ fn main() -> Result<()> {
|
|
|
531
534
|
else if Some(&resp.id) == app.state.pending_bundle_check_id.as_ref() {
|
|
532
535
|
app.state.pending_bundle_check_id = None;
|
|
533
536
|
app.state.setup_portal.detecting = false;
|
|
537
|
+
app.state.setup_portal.detecting_since = None;
|
|
534
538
|
app.state.setup_portal.error = Some(error_msg.clone());
|
|
535
539
|
app.add_log(format!("✗ [{}] Bundle check failed: {}", short_id, error_msg));
|
|
536
540
|
}
|
|
@@ -639,11 +643,27 @@ fn main() -> Result<()> {
|
|
|
639
643
|
previous_screen = Some(current_screen);
|
|
640
644
|
}
|
|
641
645
|
|
|
646
|
+
// Setup Portal: if detection has been running too long, unstick so user can ESC or retry
|
|
647
|
+
if app.state.navigation.current_screen() == &screens::Screen::SetupPortal
|
|
648
|
+
&& app.state.setup_portal.detecting
|
|
649
|
+
{
|
|
650
|
+
if let Some(since) = app.state.setup_portal.detecting_since {
|
|
651
|
+
if since.elapsed() >= Duration::from_secs(8) {
|
|
652
|
+
app.state.setup_portal.detecting = false;
|
|
653
|
+
app.state.setup_portal.detecting_since = None;
|
|
654
|
+
app.state.setup_portal.error = Some("Detection timed out. Press ESC to close or try again.".to_string());
|
|
655
|
+
app.add_log("[SETUP] Detection timed out".to_string());
|
|
656
|
+
app.request_render("setup_detect_timeout");
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
642
661
|
// ┌─────────────────────────────────────────────────────────┐
|
|
643
662
|
// │ STEP 4: CHECK FOR INPUT (non-blocking with timeout) │
|
|
644
663
|
// └─────────────────────────────────────────────────────────┘
|
|
645
664
|
// OPTIMIZATION: Reduced poll timeout to 1ms for faster input detection
|
|
646
665
|
// This allows loop to run ~1000 times/second when idle, but input is detected immediately
|
|
666
|
+
// Handle ESC on both Press and Release so we never miss it (e.g. when stuck on "Detecting...")
|
|
647
667
|
if crossterm::event::poll(Duration::from_millis(1))? {
|
|
648
668
|
let on_setup = app.state.navigation.current_screen() == &screens::Screen::SetupPortal;
|
|
649
669
|
match event::read()? {
|
|
@@ -651,7 +671,9 @@ fn main() -> Result<()> {
|
|
|
651
671
|
if on_setup {
|
|
652
672
|
debug_log::log_input("Key", &format!("{:?}", key));
|
|
653
673
|
}
|
|
654
|
-
|
|
674
|
+
let should_handle = key.kind == KeyEventKind::Press
|
|
675
|
+
|| (key.code == KeyCode::Esc && key.kind == KeyEventKind::Release);
|
|
676
|
+
if should_handle {
|
|
655
677
|
if app.handle_input(key, &mut io_handler, ws_client.as_ref())? {
|
|
656
678
|
break; // Exit requested
|
|
657
679
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.73",
|
|
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.73: Setup Portal no longer freezes on Detecting (timeout + ESC-on-Release). ⚠️ Pre-MVP / Development Phase",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"4runr": "dist/index.js",
|