4runr-os 2.10.43 → 2.10.45
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 +45 -31
- package/mk3-tui/src/main.rs +30 -3
- package/mk3-tui/src/ui/portal_monitoring.rs +12 -9
- package/package.json +2 -2
package/mk3-tui/src/app.rs
CHANGED
|
@@ -311,7 +311,7 @@ impl Default for PortalMonitoringState {
|
|
|
311
311
|
viewport_lines: 18,
|
|
312
312
|
last_refresh: None,
|
|
313
313
|
auto_refresh_interval: Duration::from_secs(5),
|
|
314
|
-
auto_refresh_enabled:
|
|
314
|
+
auto_refresh_enabled: false,
|
|
315
315
|
last_http_for_delta: None,
|
|
316
316
|
last_instant_for_delta: None,
|
|
317
317
|
section_overrides: HashMap::new(),
|
|
@@ -936,6 +936,17 @@ impl App {
|
|
|
936
936
|
self.request_immediate_render("portal_obs_scroll");
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
+
fn cancel_portal_monitoring_requests(&mut self) {
|
|
940
|
+
self.state.pending_gateway_observability_id = None;
|
|
941
|
+
self.state.pending_monitoring_refresh_id = None;
|
|
942
|
+
self.state.pending_monitoring_logs_id = None;
|
|
943
|
+
self.state.pending_monitoring_drill_id = None;
|
|
944
|
+
self.state.portal_monitoring.loading = false;
|
|
945
|
+
self.state.portal_monitoring.section_refresh_loading = None;
|
|
946
|
+
self.state.portal_monitoring.logs_fetch_loading = false;
|
|
947
|
+
self.state.portal_monitoring.metrics_drill_loading = false;
|
|
948
|
+
}
|
|
949
|
+
|
|
939
950
|
/// CLI ↔ TUI WebSocket lost: drop Gateway link UI and leave Portal Monitoring / Connection Portal so the session does not appear still "connected".
|
|
940
951
|
pub fn on_cli_backend_disconnect(&mut self) {
|
|
941
952
|
use crate::screens::Screen;
|
|
@@ -2535,7 +2546,9 @@ impl App {
|
|
|
2535
2546
|
|
|
2536
2547
|
// M — Portal Monitoring (after successful connect)
|
|
2537
2548
|
KeyCode::Char('m') | KeyCode::Char('M')
|
|
2538
|
-
if self.state.connection_portal.connection_success
|
|
2549
|
+
if self.state.connection_portal.connection_success
|
|
2550
|
+
|| (matches!(self.state.operation_mode, OperationMode::Connected)
|
|
2551
|
+
&& self.state.gateway_url.is_some()) =>
|
|
2539
2552
|
{
|
|
2540
2553
|
self.state
|
|
2541
2554
|
.navigation
|
|
@@ -2750,37 +2763,13 @@ impl App {
|
|
|
2750
2763
|
self.request_immediate_render("portal_help_open");
|
|
2751
2764
|
return Ok(false);
|
|
2752
2765
|
}
|
|
2753
|
-
// R is
|
|
2754
|
-
// section → `monitoring.refresh` for that section only (cheaper; matches expanded detail).
|
|
2766
|
+
// R is deliberately global: refresh the full snapshot without changing the current view.
|
|
2755
2767
|
if key.code == KeyCode::Char('r') || key.code == KeyCode::Char('R') {
|
|
2756
2768
|
if let Some(ws) = ws_client {
|
|
2757
|
-
let sections = MonitoringSection::all();
|
|
2758
|
-
let idx = self
|
|
2759
|
-
.state
|
|
2760
|
-
.advanced_monitoring
|
|
2761
|
-
.monitoring_state
|
|
2762
|
-
.selected_index;
|
|
2763
|
-
let current = sections.get(idx).copied();
|
|
2764
2769
|
self.state.portal_observability_last_poll = None;
|
|
2765
|
-
self.
|
|
2766
|
-
self.state.pending_monitoring_refresh_id = None;
|
|
2767
|
-
self.state.pending_monitoring_logs_id = None;
|
|
2768
|
-
self.state.pending_monitoring_drill_id = None;
|
|
2769
|
-
self.state.portal_monitoring.loading = false;
|
|
2770
|
-
self.state.portal_monitoring.section_refresh_loading = None;
|
|
2771
|
-
self.state.portal_monitoring.logs_fetch_loading = false;
|
|
2772
|
-
self.state.portal_monitoring.metrics_drill = None;
|
|
2773
|
-
self.state.portal_monitoring.metrics_drill_lines.clear();
|
|
2774
|
-
self.state.portal_monitoring.metrics_drill_loading = false;
|
|
2770
|
+
self.cancel_portal_monitoring_requests();
|
|
2775
2771
|
self.state.portal_monitoring.last_refresh = Some(std::time::Instant::now());
|
|
2776
|
-
|
|
2777
|
-
Some(MonitoringSection::Overview) | None => {
|
|
2778
|
-
self.begin_portal_observability_request(ws);
|
|
2779
|
-
}
|
|
2780
|
-
Some(sec) => {
|
|
2781
|
-
self.begin_monitoring_refresh_request(ws, sec);
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2772
|
+
self.begin_portal_observability_request(ws);
|
|
2784
2773
|
self.request_immediate_render("portal_obs_refresh");
|
|
2785
2774
|
} else {
|
|
2786
2775
|
self.state.portal_monitoring.error =
|
|
@@ -2790,6 +2779,29 @@ impl App {
|
|
|
2790
2779
|
return Ok(false);
|
|
2791
2780
|
}
|
|
2792
2781
|
if key.code == KeyCode::Char('l') || key.code == KeyCode::Char('L') {
|
|
2782
|
+
let logs_open = self
|
|
2783
|
+
.state
|
|
2784
|
+
.advanced_monitoring
|
|
2785
|
+
.monitoring_state
|
|
2786
|
+
.selected_section
|
|
2787
|
+
== Some(MonitoringSection::Logs)
|
|
2788
|
+
&& self
|
|
2789
|
+
.state
|
|
2790
|
+
.advanced_monitoring
|
|
2791
|
+
.monitoring_state
|
|
2792
|
+
.sections
|
|
2793
|
+
.get(&MonitoringSection::Logs)
|
|
2794
|
+
.map(|section| section.expanded)
|
|
2795
|
+
.unwrap_or(false);
|
|
2796
|
+
if logs_open && !self.state.portal_monitoring.logs_fetch_loading {
|
|
2797
|
+
self.state
|
|
2798
|
+
.advanced_monitoring
|
|
2799
|
+
.monitoring_state
|
|
2800
|
+
.collapse_section(MonitoringSection::Logs);
|
|
2801
|
+
self.state.portal_monitoring.scroll_offset = 0;
|
|
2802
|
+
self.request_immediate_render("portal_monitoring_logs_close");
|
|
2803
|
+
return Ok(false);
|
|
2804
|
+
}
|
|
2793
2805
|
self.state
|
|
2794
2806
|
.advanced_monitoring
|
|
2795
2807
|
.monitoring_state
|
|
@@ -2799,6 +2811,7 @@ impl App {
|
|
|
2799
2811
|
.monitoring_state
|
|
2800
2812
|
.expand_section(MonitoringSection::Logs);
|
|
2801
2813
|
if let Some(ws) = ws_client {
|
|
2814
|
+
self.cancel_portal_monitoring_requests();
|
|
2802
2815
|
self.begin_monitoring_logs_request(ws);
|
|
2803
2816
|
let inner_h = self.state.portal_monitoring.viewport_lines.max(5);
|
|
2804
2817
|
let sw = self.state.portal_monitoring.summary_clip_width.max(24);
|
|
@@ -2878,6 +2891,7 @@ impl App {
|
|
|
2878
2891
|
MonitoringSection::Dependencies,
|
|
2879
2892
|
);
|
|
2880
2893
|
if let Some(ws) = ws_client {
|
|
2894
|
+
self.cancel_portal_monitoring_requests();
|
|
2881
2895
|
self.begin_dependencies_detail_drill(ws);
|
|
2882
2896
|
self.request_immediate_render("portal_deps_drill");
|
|
2883
2897
|
} else {
|
|
@@ -2907,6 +2921,7 @@ impl App {
|
|
|
2907
2921
|
MonitoringSection::System,
|
|
2908
2922
|
);
|
|
2909
2923
|
if let Some(ws) = ws_client {
|
|
2924
|
+
self.cancel_portal_monitoring_requests();
|
|
2910
2925
|
self.begin_system_diagnostics_request(ws);
|
|
2911
2926
|
self.request_immediate_render("portal_system_diagnostics");
|
|
2912
2927
|
} else {
|
|
@@ -2935,6 +2950,7 @@ impl App {
|
|
|
2935
2950
|
MonitoringSection::Metrics,
|
|
2936
2951
|
);
|
|
2937
2952
|
if let Some(ws) = ws_client {
|
|
2953
|
+
self.cancel_portal_monitoring_requests();
|
|
2938
2954
|
let panel = self
|
|
2939
2955
|
.state
|
|
2940
2956
|
.portal_monitoring
|
|
@@ -3004,7 +3020,6 @@ impl App {
|
|
|
3004
3020
|
.monitoring_state
|
|
3005
3021
|
.selected_section
|
|
3006
3022
|
== Some(MonitoringSection::Logs)
|
|
3007
|
-
&& self.state.portal_monitoring.scroll_offset > 0
|
|
3008
3023
|
{
|
|
3009
3024
|
self.state.portal_monitoring.scroll_offset =
|
|
3010
3025
|
self.state.portal_monitoring.scroll_offset.saturating_sub(1);
|
|
@@ -3025,7 +3040,6 @@ impl App {
|
|
|
3025
3040
|
.monitoring_state
|
|
3026
3041
|
.selected_section
|
|
3027
3042
|
== Some(MonitoringSection::Logs)
|
|
3028
|
-
&& self.state.portal_monitoring.scroll_offset < max_scroll
|
|
3029
3043
|
{
|
|
3030
3044
|
self.state.portal_monitoring.scroll_offset =
|
|
3031
3045
|
(self.state.portal_monitoring.scroll_offset + 1).min(max_scroll);
|
package/mk3-tui/src/main.rs
CHANGED
|
@@ -890,19 +890,46 @@ fn main() -> Result<()> {
|
|
|
890
890
|
.to_string(),
|
|
891
891
|
);
|
|
892
892
|
}
|
|
893
|
+
let preserve_scroll =
|
|
894
|
+
app.state.portal_monitoring.scroll_offset;
|
|
895
|
+
let preserve_metrics_drill =
|
|
896
|
+
app.state.portal_monitoring.metrics_drill;
|
|
897
|
+
let preserve_metrics_drill_lines = app
|
|
898
|
+
.state
|
|
899
|
+
.portal_monitoring
|
|
900
|
+
.metrics_drill_lines
|
|
901
|
+
.clone();
|
|
902
|
+
let preserve_logs = app
|
|
903
|
+
.state
|
|
904
|
+
.portal_monitoring
|
|
905
|
+
.section_overrides
|
|
906
|
+
.get(&crate::monitoring::MonitoringSection::Logs)
|
|
907
|
+
.cloned();
|
|
893
908
|
app.state.portal_monitoring.last_updated =
|
|
894
909
|
Some(snapshot);
|
|
895
910
|
app.state.portal_monitoring.content_lines = lines;
|
|
896
911
|
app.state.portal_monitoring.section_overrides.clear();
|
|
912
|
+
if let Some(logs) = preserve_logs {
|
|
913
|
+
app.state
|
|
914
|
+
.portal_monitoring
|
|
915
|
+
.section_overrides
|
|
916
|
+
.insert(
|
|
917
|
+
crate::monitoring::MonitoringSection::Logs,
|
|
918
|
+
logs,
|
|
919
|
+
);
|
|
920
|
+
}
|
|
897
921
|
app.state.portal_monitoring.section_refresh_loading =
|
|
898
922
|
None;
|
|
899
923
|
app.state.portal_monitoring.logs_fetch_loading = false;
|
|
900
|
-
app.state.portal_monitoring.metrics_drill =
|
|
901
|
-
|
|
924
|
+
app.state.portal_monitoring.metrics_drill =
|
|
925
|
+
preserve_metrics_drill;
|
|
926
|
+
app.state.portal_monitoring.metrics_drill_lines =
|
|
927
|
+
preserve_metrics_drill_lines;
|
|
902
928
|
app.state.portal_monitoring.metrics_drill_loading =
|
|
903
929
|
false;
|
|
904
930
|
app.state.portal_monitoring.error = None;
|
|
905
|
-
app.state.portal_monitoring.scroll_offset =
|
|
931
|
+
app.state.portal_monitoring.scroll_offset =
|
|
932
|
+
preserve_scroll;
|
|
906
933
|
} else {
|
|
907
934
|
app.state.portal_monitoring.error = Some(
|
|
908
935
|
"Unexpected observability response.".to_string(),
|
|
@@ -878,7 +878,7 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
|
|
|
878
878
|
]);
|
|
879
879
|
|
|
880
880
|
let keys_hint = Line::from(vec![Span::styled(
|
|
881
|
-
"R
|
|
881
|
+
"R full refresh · L logs · wheel/Pg scroll · H metrics trends · → metrics drill · T dependencies · S system · A live",
|
|
882
882
|
Style::default().fg(TEXT_DIM),
|
|
883
883
|
)]);
|
|
884
884
|
|
|
@@ -983,7 +983,7 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
|
|
|
983
983
|
Span::styled("expand ", Style::default().fg(TEXT_DIM)),
|
|
984
984
|
Span::styled("│ ", Style::default().fg(SEPARATOR_COLOR)),
|
|
985
985
|
Span::styled("R ", Style::default().fg(CYBER_CYAN).bold()),
|
|
986
|
-
Span::styled("
|
|
986
|
+
Span::styled("refresh ", Style::default().fg(TEXT_DIM)),
|
|
987
987
|
Span::styled("│ ", Style::default().fg(SEPARATOR_COLOR)),
|
|
988
988
|
Span::styled("L ", Style::default().fg(CYBER_CYAN).bold()),
|
|
989
989
|
Span::styled("logs ", Style::default().fg(TEXT_DIM)),
|
|
@@ -1032,16 +1032,19 @@ pub fn render(f: &mut Frame, state: &mut AppState) {
|
|
|
1032
1032
|
)]),
|
|
1033
1033
|
Line::from(""),
|
|
1034
1034
|
Line::from("Navigation"),
|
|
1035
|
-
Line::from(
|
|
1035
|
+
Line::from(
|
|
1036
|
+
" ↑/↓ select section Enter/Space expand/collapse PgUp/PgDn/mouse scroll",
|
|
1037
|
+
),
|
|
1038
|
+
Line::from(" When Logs is selected, ↑/↓ scroll log content first."),
|
|
1036
1039
|
Line::from(" ESC close help / return to Main"),
|
|
1037
1040
|
Line::from(""),
|
|
1038
1041
|
Line::from("Actions"),
|
|
1039
|
-
Line::from(" R refresh
|
|
1040
|
-
Line::from(
|
|
1041
|
-
|
|
1042
|
-
),
|
|
1043
|
-
Line::from("
|
|
1044
|
-
Line::from("
|
|
1042
|
+
Line::from(" R full snapshot refresh without closing your current section"),
|
|
1043
|
+
Line::from(" L jump to Logs + fetch Gateway logs"),
|
|
1044
|
+
Line::from(" H jump to Metrics + toggle trends → Metrics drill ← leave drill"),
|
|
1045
|
+
Line::from(" T jump to Dependencies detail S jump to System diagnostics"),
|
|
1046
|
+
Line::from(" A toggle live auto-refresh (off by default for stable reading)"),
|
|
1047
|
+
Line::from(" E export diagnostics JSON to the current working directory"),
|
|
1045
1048
|
Line::from(""),
|
|
1046
1049
|
Line::from("Recovery"),
|
|
1047
1050
|
Line::from(
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "4runr-os",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.45",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.
|
|
5
|
+
"description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.45: Fixes Portal Monitoring log toggle, log-bottom scroll, and monitor re-entry from linked Gateway sessions. v2.10.44: Stabilizes Portal Monitoring reading mode, global refresh, logs, and shortcut behavior.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"4runr": "dist/index.js",
|