4runr-os 2.10.47 → 2.10.49

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.
@@ -746,8 +746,7 @@ impl App {
746
746
  ws: &WebSocketClient,
747
747
  section: MonitoringSection,
748
748
  ) {
749
- if self.state.pending_gateway_observability_id.is_some()
750
- || self.state.pending_monitoring_refresh_id.is_some()
749
+ if self.state.pending_monitoring_refresh_id.is_some()
751
750
  || self.state.pending_monitoring_logs_id.is_some()
752
751
  || self.state.pending_monitoring_drill_id.is_some()
753
752
  {
@@ -775,8 +774,7 @@ impl App {
775
774
 
776
775
  /// Phase 2: fetch Gateway log buffer (`monitoring.logs`).
777
776
  pub fn begin_monitoring_logs_request(&mut self, ws: &WebSocketClient) {
778
- if self.state.pending_gateway_observability_id.is_some()
779
- || self.state.pending_monitoring_refresh_id.is_some()
777
+ if self.state.pending_monitoring_refresh_id.is_some()
780
778
  || self.state.pending_monitoring_logs_id.is_some()
781
779
  || self.state.pending_monitoring_drill_id.is_some()
782
780
  {
@@ -807,8 +805,7 @@ impl App {
807
805
  ws: &WebSocketClient,
808
806
  panel: MetricsDrillPanel,
809
807
  ) {
810
- if self.state.pending_gateway_observability_id.is_some()
811
- || self.state.pending_monitoring_refresh_id.is_some()
808
+ if self.state.pending_monitoring_refresh_id.is_some()
812
809
  || self.state.pending_monitoring_logs_id.is_some()
813
810
  || self.state.pending_monitoring_drill_id.is_some()
814
811
  {
@@ -838,8 +835,7 @@ impl App {
838
835
 
839
836
  /// Phase 3: dependency pools + queue counts (`dependencies/detail`).
840
837
  pub fn begin_dependencies_detail_drill(&mut self, ws: &WebSocketClient) {
841
- if self.state.pending_gateway_observability_id.is_some()
842
- || self.state.pending_monitoring_refresh_id.is_some()
838
+ if self.state.pending_monitoring_refresh_id.is_some()
843
839
  || self.state.pending_monitoring_logs_id.is_some()
844
840
  || self.state.pending_monitoring_drill_id.is_some()
845
841
  {
@@ -867,8 +863,7 @@ impl App {
867
863
 
868
864
  /// Phase 4: run local CLI/host diagnostics for the System section.
869
865
  pub fn begin_system_diagnostics_request(&mut self, ws: &WebSocketClient) {
870
- if self.state.pending_gateway_observability_id.is_some()
871
- || self.state.pending_monitoring_refresh_id.is_some()
866
+ if self.state.pending_monitoring_refresh_id.is_some()
872
867
  || self.state.pending_monitoring_logs_id.is_some()
873
868
  || self.state.pending_monitoring_drill_id.is_some()
874
869
  {
@@ -936,15 +931,24 @@ impl App {
936
931
  self.request_immediate_render("portal_obs_scroll");
937
932
  }
938
933
 
939
- fn cancel_portal_monitoring_requests(&mut self) {
940
- self.state.pending_gateway_observability_id = None;
934
+ /// Drop in-flight `monitoring.*` / drill work without orphaning `gateway.observability`
935
+ /// (clearing that id makes the snapshot response a no-op and can stall the portal).
936
+ fn cancel_portal_monitoring_aux_requests(&mut self) {
941
937
  self.state.pending_monitoring_refresh_id = None;
942
938
  self.state.pending_monitoring_logs_id = None;
943
939
  self.state.pending_monitoring_drill_id = None;
944
- self.state.portal_monitoring.loading = false;
945
940
  self.state.portal_monitoring.section_refresh_loading = None;
946
941
  self.state.portal_monitoring.logs_fetch_loading = false;
947
942
  self.state.portal_monitoring.metrics_drill_loading = false;
943
+ if self.state.pending_gateway_observability_id.is_none() {
944
+ self.state.portal_monitoring.loading = false;
945
+ }
946
+ }
947
+
948
+ fn cancel_portal_monitoring_requests(&mut self) {
949
+ self.cancel_portal_monitoring_aux_requests();
950
+ self.state.pending_gateway_observability_id = None;
951
+ self.state.portal_monitoring.loading = false;
948
952
  }
949
953
 
950
954
  /// CLI ↔ TUI WebSocket lost: drop Gateway link UI and leave Portal Monitoring / Connection Portal so the session does not appear still "connected".
@@ -2811,7 +2815,7 @@ impl App {
2811
2815
  .monitoring_state
2812
2816
  .expand_section(MonitoringSection::Logs);
2813
2817
  if let Some(ws) = ws_client {
2814
- self.cancel_portal_monitoring_requests();
2818
+ self.cancel_portal_monitoring_aux_requests();
2815
2819
  self.begin_monitoring_logs_request(ws);
2816
2820
  let inner_h = self.state.portal_monitoring.viewport_lines.max(5);
2817
2821
  let sw = self.state.portal_monitoring.summary_clip_width.max(24);
@@ -2891,7 +2895,7 @@ impl App {
2891
2895
  MonitoringSection::Dependencies,
2892
2896
  );
2893
2897
  if let Some(ws) = ws_client {
2894
- self.cancel_portal_monitoring_requests();
2898
+ self.cancel_portal_monitoring_aux_requests();
2895
2899
  self.begin_dependencies_detail_drill(ws);
2896
2900
  self.request_immediate_render("portal_deps_drill");
2897
2901
  } else {
@@ -2903,7 +2907,33 @@ impl App {
2903
2907
  }
2904
2908
 
2905
2909
  // Phase 4: diagnostics for the local CLI/TUI bridge + Gateway reachability.
2910
+ // S toggles like L for logs: second press dismisses the drill (does not cancel in-flight
2911
+ // gateway.observability — that was orphaning snapshots and making S feel "stuck").
2906
2912
  if key.code == KeyCode::Char('s') || key.code == KeyCode::Char('S') {
2913
+ let system_lines_open = self
2914
+ .state
2915
+ .portal_monitoring
2916
+ .section_overrides
2917
+ .contains_key(&MonitoringSection::System);
2918
+ let system_request_inflight = self
2919
+ .state
2920
+ .portal_monitoring
2921
+ .section_refresh_loading
2922
+ == Some(MonitoringSection::System);
2923
+ if system_lines_open && !system_request_inflight {
2924
+ self.state
2925
+ .advanced_monitoring
2926
+ .monitoring_state
2927
+ .collapse_section(MonitoringSection::System);
2928
+ self.state
2929
+ .portal_monitoring
2930
+ .section_overrides
2931
+ .remove(&MonitoringSection::System);
2932
+ self.state.portal_monitoring.scroll_offset = 0;
2933
+ self.state.portal_monitoring.error = None;
2934
+ self.request_immediate_render("portal_system_diagnostics_close");
2935
+ return Ok(false);
2936
+ }
2907
2937
  self.state
2908
2938
  .advanced_monitoring
2909
2939
  .monitoring_state
@@ -2921,7 +2951,7 @@ impl App {
2921
2951
  MonitoringSection::System,
2922
2952
  );
2923
2953
  if let Some(ws) = ws_client {
2924
- self.cancel_portal_monitoring_requests();
2954
+ self.cancel_portal_monitoring_aux_requests();
2925
2955
  self.begin_system_diagnostics_request(ws);
2926
2956
  self.request_immediate_render("portal_system_diagnostics");
2927
2957
  } else {
@@ -2950,7 +2980,7 @@ impl App {
2950
2980
  MonitoringSection::Metrics,
2951
2981
  );
2952
2982
  if let Some(ws) = ws_client {
2953
- self.cancel_portal_monitoring_requests();
2983
+ self.cancel_portal_monitoring_aux_requests();
2954
2984
  let panel = self
2955
2985
  .state
2956
2986
  .portal_monitoring
@@ -905,6 +905,25 @@ fn main() -> Result<()> {
905
905
  .section_overrides
906
906
  .get(&crate::monitoring::MonitoringSection::Logs)
907
907
  .cloned();
908
+ // System diagnostics (`S`) and dependency drill (`T`) live in
909
+ // `section_overrides`. Full observability runs as soon as no pending
910
+ // drill id exists, so we must restore these or the UI "blinks closed".
911
+ let preserve_system = app
912
+ .state
913
+ .portal_monitoring
914
+ .section_overrides
915
+ .get(
916
+ &crate::monitoring::MonitoringSection::System,
917
+ )
918
+ .cloned();
919
+ let preserve_dependencies = app
920
+ .state
921
+ .portal_monitoring
922
+ .section_overrides
923
+ .get(
924
+ &crate::monitoring::MonitoringSection::Dependencies,
925
+ )
926
+ .cloned();
908
927
  app.state.portal_monitoring.last_updated =
909
928
  Some(snapshot);
910
929
  app.state.portal_monitoring.content_lines = lines;
@@ -918,6 +937,24 @@ fn main() -> Result<()> {
918
937
  logs,
919
938
  );
920
939
  }
940
+ if let Some(system) = preserve_system {
941
+ app.state
942
+ .portal_monitoring
943
+ .section_overrides
944
+ .insert(
945
+ crate::monitoring::MonitoringSection::System,
946
+ system,
947
+ );
948
+ }
949
+ if let Some(deps) = preserve_dependencies {
950
+ app.state
951
+ .portal_monitoring
952
+ .section_overrides
953
+ .insert(
954
+ crate::monitoring::MonitoringSection::Dependencies,
955
+ deps,
956
+ );
957
+ }
921
958
  app.state.portal_monitoring.section_refresh_loading =
922
959
  None;
923
960
  app.state.portal_monitoring.logs_fetch_loading = false;
@@ -720,7 +720,7 @@ fn build_body_lines(state: &AppState, summary_width: usize) -> Vec<Line<'static>
720
720
  "If results stay empty, nothing may be writing to the Gateway log ring buffer yet.".into(),
721
721
  ],
722
722
  MonitoringSection::System => vec![
723
- "Press S to fetch CLI process + host OS stats and run diagnostics.".into(),
723
+ "Press S to fetch CLI/host stats + diagnostics; press S again to dismiss.".into(),
724
724
  String::new(),
725
725
  "MK3 TUI runtime".into(),
726
726
  format!(
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "4runr-os",
3
- "version": "2.10.47",
3
+ "version": "2.10.49",
4
4
  "type": "module",
5
- "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.47: Clarifies Portal Monitoring System stats use S while R remains global refresh. v2.10.46: Restores Portal Monitoring section navigation after closing Logs.",
5
+ "description": "4Runr AI Agent OS - Secure terminal interface for AI agents. v2.10.49: Portal Monitoring S toggles System diagnostics (press again to dismiss); aux cancel preserves in-flight observability; drills work during snapshot load. v2.10.48: Preserve System/Dependencies on observability refresh.",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "4runr": "dist/index.js",