4runr-os 2.10.39 → 2.10.41

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.
Files changed (51) hide show
  1. package/apps/gateway/dist/apps/gateway/src/index.js +14 -4
  2. package/apps/gateway/dist/apps/gateway/src/index.js.map +1 -1
  3. package/apps/gateway/dist/apps/gateway/src/metrics/monitoring-detail.d.ts +18 -0
  4. package/apps/gateway/dist/apps/gateway/src/metrics/monitoring-detail.d.ts.map +1 -0
  5. package/apps/gateway/dist/apps/gateway/src/metrics/monitoring-detail.js +117 -0
  6. package/apps/gateway/dist/apps/gateway/src/metrics/monitoring-detail.js.map +1 -0
  7. package/apps/gateway/dist/apps/gateway/src/middleware/log-capture.d.ts +2 -0
  8. package/apps/gateway/dist/apps/gateway/src/middleware/log-capture.d.ts.map +1 -0
  9. package/apps/gateway/dist/apps/gateway/src/middleware/log-capture.js +54 -0
  10. package/apps/gateway/dist/apps/gateway/src/middleware/log-capture.js.map +1 -0
  11. package/apps/gateway/dist/apps/gateway/src/routes/monitoring.d.ts +15 -0
  12. package/apps/gateway/dist/apps/gateway/src/routes/monitoring.d.ts.map +1 -0
  13. package/apps/gateway/dist/apps/gateway/src/routes/monitoring.js +164 -0
  14. package/apps/gateway/dist/apps/gateway/src/routes/monitoring.js.map +1 -0
  15. package/apps/gateway/package-lock.json +204 -353
  16. package/apps/gateway/src/index.ts +27 -8
  17. package/apps/gateway/src/metrics/monitoring-detail.ts +162 -0
  18. package/apps/gateway/src/middleware/log-capture.ts +70 -0
  19. package/apps/gateway/src/routes/monitoring.ts +298 -0
  20. package/dist/gateway-client.d.ts +2 -0
  21. package/dist/gateway-client.d.ts.map +1 -1
  22. package/dist/gateway-client.js +22 -0
  23. package/dist/gateway-client.js.map +1 -1
  24. package/dist/tui-handlers.js +498 -0
  25. package/dist/tui-handlers.js.map +1 -1
  26. package/mk3-tui/src/app/render_scheduler.rs +111 -112
  27. package/mk3-tui/src/app.rs +1078 -295
  28. package/mk3-tui/src/debug_log.rs +131 -124
  29. package/mk3-tui/src/io/mod.rs +63 -66
  30. package/mk3-tui/src/io/protocol.rs +14 -15
  31. package/mk3-tui/src/io/stdio.rs +31 -32
  32. package/mk3-tui/src/io/ws.rs +25 -32
  33. package/mk3-tui/src/main.rs +774 -212
  34. package/mk3-tui/src/monitoring/mod.rs +428 -0
  35. package/mk3-tui/src/screens/mod.rs +53 -39
  36. package/mk3-tui/src/storage/cache.rs +221 -224
  37. package/mk3-tui/src/storage/mod.rs +5 -6
  38. package/mk3-tui/src/ui/agent_builder.rs +1148 -922
  39. package/mk3-tui/src/ui/agent_list.rs +344 -295
  40. package/mk3-tui/src/ui/boot.rs +145 -148
  41. package/mk3-tui/src/ui/connection_portal.rs +121 -98
  42. package/mk3-tui/src/ui/help.rs +340 -284
  43. package/mk3-tui/src/ui/layout.rs +966 -803
  44. package/mk3-tui/src/ui/mod.rs +1 -1
  45. package/mk3-tui/src/ui/portal_monitoring.rs +1027 -147
  46. package/mk3-tui/src/ui/run_manager.rs +784 -764
  47. package/mk3-tui/src/ui/safe_viewport.rs +236 -235
  48. package/mk3-tui/src/ui/settings.rs +414 -362
  49. package/mk3-tui/src/ui/setup_portal.rs +158 -101
  50. package/mk3-tui/src/websocket.rs +315 -308
  51. package/package.json +2 -2
@@ -1,124 +1,131 @@
1
- //! File-based debug logger for Setup Portal.
2
- //! When SETUP_PORTAL_DEBUG=1 or SETUP_PORTAL_DEBUG_FILE is set, all inputs and render state
3
- //! are written to a file so you can capture the full trace when reproducing the navigation bug.
4
- //!
5
- //! Usage:
6
- //! set SETUP_PORTAL_DEBUG_FILE=setup-portal-debug.log
7
- //! mk3-tui (or 4r)
8
- //! Then open Setup Portal (windowed), reproduce the bug, exit. Inspect setup-portal-debug.log.
9
-
10
- use std::io::Write;
11
- use std::sync::Mutex;
12
- use std::sync::OnceLock;
13
- use std::time::{SystemTime, UNIX_EPOCH};
14
-
15
- fn enabled() -> bool {
16
- std::env::var("SETUP_PORTAL_DEBUG").as_deref() == Ok("1")
17
- || std::env::var("SETUP_PORTAL_DEBUG_FILE").is_ok()
18
- }
19
-
20
- fn path() -> String {
21
- std::env::var("SETUP_PORTAL_DEBUG_FILE")
22
- .unwrap_or_else(|_| "setup-portal-debug.log".to_string())
23
- }
24
-
25
- static FILE: OnceLock<Mutex<Option<std::io::BufWriter<std::fs::File>>>> = OnceLock::new();
26
-
27
- fn ensure_open() -> bool {
28
- if !enabled() {
29
- return false;
30
- }
31
- let mutex = FILE.get_or_init(|| Mutex::new(None));
32
- let mut guard = mutex.lock().unwrap();
33
- if guard.is_none() {
34
- let path = path();
35
- match std::fs::OpenOptions::new()
36
- .create(true)
37
- .append(true)
38
- .open(&path)
39
- {
40
- Ok(file_handle) => {
41
- // Resolve full path so user always knows where the log is
42
- let full_path: String = std::path::Path::new(&path)
43
- .canonicalize()
44
- .map(|p| p.display().to_string())
45
- .or_else(|_| std::env::current_dir().map(|cwd| cwd.join(&path).display().to_string()))
46
- .unwrap_or_else(|_| path.clone());
47
- let _ = writeln!(
48
- std::io::stderr(),
49
- "[SETUP_PORTAL_DEBUG] Log file: {}",
50
- full_path
51
- );
52
- let mut w = std::io::BufWriter::new(file_handle);
53
- let banner = format!("{} === Setup Portal debug log opened: {} ===\n", timestamp(), full_path);
54
- let _ = w.write_all(banner.as_bytes());
55
- let _ = w.flush();
56
- *guard = Some(w);
57
- return true;
58
- }
59
- Err(e) => {
60
- let _ = writeln!(
61
- std::io::stderr(),
62
- "[SETUP_PORTAL_DEBUG] Failed to open \"{}\": {}",
63
- path, e
64
- );
65
- return false;
66
- }
67
- }
68
- }
69
- true
70
- }
71
-
72
- fn log_raw(msg: &str) {
73
- if !enabled() {
74
- return;
75
- }
76
- if !ensure_open() {
77
- return;
78
- }
79
- let mutex = FILE.get().unwrap();
80
- let mut guard = mutex.lock().unwrap();
81
- if let Some(ref mut w) = *guard {
82
- let _ = w.write_all(msg.as_bytes());
83
- let _ = w.write_all(b"\n");
84
- let _ = w.flush();
85
- }
86
- }
87
-
88
- fn timestamp() -> String {
89
- SystemTime::now()
90
- .duration_since(UNIX_EPOCH)
91
- .map(|d| format!("{}.{:03}", d.as_secs(), d.subsec_millis()))
92
- .unwrap_or_else(|_| "?.???".to_string())
93
- }
94
-
95
- /// Log a line with timestamp. Call from main or setup_portal when debug file is enabled.
96
- pub fn log(msg: &str) {
97
- log_raw(&format!("{} {}", timestamp(), msg));
98
- }
99
-
100
- /// Log screen switch (enter/leave Setup Portal).
101
- pub fn log_screen(from: &str, to: &str) {
102
- log(&format!("SCREEN {} -> {}", from, to));
103
- }
104
-
105
- /// Log an input event (key, mouse, resize).
106
- pub fn log_input(kind: &str, detail: &str) {
107
- log(&format!("INPUT {} {}", kind, detail));
108
- }
109
-
110
- /// Log render state (dims, rects, selected option). Throttled by caller.
111
- pub fn log_render(msg: &str) {
112
- log(&format!("RENDER {}", msg));
113
- }
114
-
115
- /// Log flicker-debug: when we clear and when we finish draw (to correlate with visible flicker).
116
- /// Writes to debug file when SETUP_PORTAL_DEBUG or SETUP_PORTAL_DEBUG_FILE is set.
117
- pub fn log_flicker_debug(event: &str, detail: &str) {
118
- let msg = format!("FLICKER {} {}", event, detail);
119
- log(&msg);
120
- // Also to stderr when file debug enabled, so "4r 2> setup-debug.log" captures it
121
- if enabled() {
122
- let _ = writeln!(std::io::stderr(), "[SETUP_PORTAL_DEBUG] {}", msg);
123
- }
124
- }
1
+ //! File-based debug logger for Setup Portal.
2
+ //! When SETUP_PORTAL_DEBUG=1 or SETUP_PORTAL_DEBUG_FILE is set, all inputs and render state
3
+ //! are written to a file so you can capture the full trace when reproducing the navigation bug.
4
+ //!
5
+ //! Usage:
6
+ //! set SETUP_PORTAL_DEBUG_FILE=setup-portal-debug.log
7
+ //! mk3-tui (or 4r)
8
+ //! Then open Setup Portal (windowed), reproduce the bug, exit. Inspect setup-portal-debug.log.
9
+
10
+ use std::io::Write;
11
+ use std::sync::Mutex;
12
+ use std::sync::OnceLock;
13
+ use std::time::{SystemTime, UNIX_EPOCH};
14
+
15
+ fn enabled() -> bool {
16
+ std::env::var("SETUP_PORTAL_DEBUG").as_deref() == Ok("1")
17
+ || std::env::var("SETUP_PORTAL_DEBUG_FILE").is_ok()
18
+ }
19
+
20
+ fn path() -> String {
21
+ std::env::var("SETUP_PORTAL_DEBUG_FILE")
22
+ .unwrap_or_else(|_| "setup-portal-debug.log".to_string())
23
+ }
24
+
25
+ static FILE: OnceLock<Mutex<Option<std::io::BufWriter<std::fs::File>>>> = OnceLock::new();
26
+
27
+ fn ensure_open() -> bool {
28
+ if !enabled() {
29
+ return false;
30
+ }
31
+ let mutex = FILE.get_or_init(|| Mutex::new(None));
32
+ let mut guard = mutex.lock().unwrap();
33
+ if guard.is_none() {
34
+ let path = path();
35
+ match std::fs::OpenOptions::new()
36
+ .create(true)
37
+ .append(true)
38
+ .open(&path)
39
+ {
40
+ Ok(file_handle) => {
41
+ // Resolve full path so user always knows where the log is
42
+ let full_path: String = std::path::Path::new(&path)
43
+ .canonicalize()
44
+ .map(|p| p.display().to_string())
45
+ .or_else(|_| {
46
+ std::env::current_dir().map(|cwd| cwd.join(&path).display().to_string())
47
+ })
48
+ .unwrap_or_else(|_| path.clone());
49
+ let _ = writeln!(
50
+ std::io::stderr(),
51
+ "[SETUP_PORTAL_DEBUG] Log file: {}",
52
+ full_path
53
+ );
54
+ let mut w = std::io::BufWriter::new(file_handle);
55
+ let banner = format!(
56
+ "{} === Setup Portal debug log opened: {} ===\n",
57
+ timestamp(),
58
+ full_path
59
+ );
60
+ let _ = w.write_all(banner.as_bytes());
61
+ let _ = w.flush();
62
+ *guard = Some(w);
63
+ return true;
64
+ }
65
+ Err(e) => {
66
+ let _ = writeln!(
67
+ std::io::stderr(),
68
+ "[SETUP_PORTAL_DEBUG] Failed to open \"{}\": {}",
69
+ path,
70
+ e
71
+ );
72
+ return false;
73
+ }
74
+ }
75
+ }
76
+ true
77
+ }
78
+
79
+ fn log_raw(msg: &str) {
80
+ if !enabled() {
81
+ return;
82
+ }
83
+ if !ensure_open() {
84
+ return;
85
+ }
86
+ let mutex = FILE.get().unwrap();
87
+ let mut guard = mutex.lock().unwrap();
88
+ if let Some(ref mut w) = *guard {
89
+ let _ = w.write_all(msg.as_bytes());
90
+ let _ = w.write_all(b"\n");
91
+ let _ = w.flush();
92
+ }
93
+ }
94
+
95
+ fn timestamp() -> String {
96
+ SystemTime::now()
97
+ .duration_since(UNIX_EPOCH)
98
+ .map(|d| format!("{}.{:03}", d.as_secs(), d.subsec_millis()))
99
+ .unwrap_or_else(|_| "?.???".to_string())
100
+ }
101
+
102
+ /// Log a line with timestamp. Call from main or setup_portal when debug file is enabled.
103
+ pub fn log(msg: &str) {
104
+ log_raw(&format!("{} {}", timestamp(), msg));
105
+ }
106
+
107
+ /// Log screen switch (enter/leave Setup Portal).
108
+ pub fn log_screen(from: &str, to: &str) {
109
+ log(&format!("SCREEN {} -> {}", from, to));
110
+ }
111
+
112
+ /// Log an input event (key, mouse, resize).
113
+ pub fn log_input(kind: &str, detail: &str) {
114
+ log(&format!("INPUT {} {}", kind, detail));
115
+ }
116
+
117
+ /// Log render state (dims, rects, selected option). Throttled by caller.
118
+ pub fn log_render(msg: &str) {
119
+ log(&format!("RENDER {}", msg));
120
+ }
121
+
122
+ /// Log flicker-debug: when we clear and when we finish draw (to correlate with visible flicker).
123
+ /// Writes to debug file when SETUP_PORTAL_DEBUG or SETUP_PORTAL_DEBUG_FILE is set.
124
+ pub fn log_flicker_debug(event: &str, detail: &str) {
125
+ let msg = format!("FLICKER {} {}", event, detail);
126
+ log(&msg);
127
+ // Also to stderr when file debug enabled, so "4r 2> setup-debug.log" captures it
128
+ if enabled() {
129
+ let _ = writeln!(std::io::stderr(), "[SETUP_PORTAL_DEBUG] {}", msg);
130
+ }
131
+ }
@@ -1,66 +1,63 @@
1
- mod protocol;
2
- mod stdio;
3
- mod ws;
4
-
5
- use crate::app::{App, Message};
6
- use anyhow::Result;
7
- use serde_json;
8
- use std::io::Write;
9
- use std::sync::mpsc;
10
- use std::thread;
11
-
12
- pub struct IoHandler {
13
- receiver: mpsc::Receiver<Message>,
14
- #[allow(dead_code)]
15
- sender: mpsc::Sender<String>,
16
- }
17
-
18
- impl IoHandler {
19
- pub fn new() -> Result<Self> {
20
- let (_tx, rx) = mpsc::channel();
21
- let (cmd_tx, _cmd_rx) = mpsc::channel();
22
-
23
- // DO NOT spawn any IO threads that read from stdin!
24
- // The TUI needs exclusive access to stdin for keyboard input.
25
- // Future: use WebSocket or named pipe for backend communication.
26
-
27
- // Command sender thread (writes to stdout, but doesn't block stdin)
28
- thread::spawn(move || {
29
- loop {
30
- match _cmd_rx.recv() {
31
- Ok(cmd) => {
32
- let cmd_json = serde_json::json!({
33
- "type": "command",
34
- "text": cmd
35
- });
36
- if let Ok(json_str) = serde_json::to_string(&cmd_json) {
37
- println!("{}", json_str);
38
- let _ = std::io::stdout().flush();
39
- }
40
- }
41
- Err(_) => break,
42
- }
43
- }
44
- });
45
-
46
- Ok(Self {
47
- receiver: rx,
48
- sender: cmd_tx,
49
- })
50
- }
51
-
52
- pub fn update(&mut self, app: &mut App) -> Result<()> {
53
- // Non-blocking receive
54
- while let Ok(message) = self.receiver.try_recv() {
55
- app.update(message);
56
- }
57
- Ok(())
58
- }
59
-
60
- #[allow(dead_code)]
61
- pub fn send_command(&mut self, cmd: String) -> Result<()> {
62
- self.sender.send(cmd)?;
63
- Ok(())
64
- }
65
- }
66
-
1
+ mod protocol;
2
+ mod stdio;
3
+ mod ws;
4
+
5
+ use crate::app::{App, Message};
6
+ use anyhow::Result;
7
+ use serde_json;
8
+ use std::io::Write;
9
+ use std::sync::mpsc;
10
+ use std::thread;
11
+
12
+ pub struct IoHandler {
13
+ receiver: mpsc::Receiver<Message>,
14
+ #[allow(dead_code)]
15
+ sender: mpsc::Sender<String>,
16
+ }
17
+
18
+ impl IoHandler {
19
+ pub fn new() -> Result<Self> {
20
+ let (_tx, rx) = mpsc::channel();
21
+ let (cmd_tx, _cmd_rx) = mpsc::channel();
22
+
23
+ // DO NOT spawn any IO threads that read from stdin!
24
+ // The TUI needs exclusive access to stdin for keyboard input.
25
+ // Future: use WebSocket or named pipe for backend communication.
26
+
27
+ // Command sender thread (writes to stdout, but doesn't block stdin)
28
+ thread::spawn(move || loop {
29
+ match _cmd_rx.recv() {
30
+ Ok(cmd) => {
31
+ let cmd_json = serde_json::json!({
32
+ "type": "command",
33
+ "text": cmd
34
+ });
35
+ if let Ok(json_str) = serde_json::to_string(&cmd_json) {
36
+ println!("{}", json_str);
37
+ let _ = std::io::stdout().flush();
38
+ }
39
+ }
40
+ Err(_) => break,
41
+ }
42
+ });
43
+
44
+ Ok(Self {
45
+ receiver: rx,
46
+ sender: cmd_tx,
47
+ })
48
+ }
49
+
50
+ pub fn update(&mut self, app: &mut App) -> Result<()> {
51
+ // Non-blocking receive
52
+ while let Ok(message) = self.receiver.try_recv() {
53
+ app.update(message);
54
+ }
55
+ Ok(())
56
+ }
57
+
58
+ #[allow(dead_code)]
59
+ pub fn send_command(&mut self, cmd: String) -> Result<()> {
60
+ self.sender.send(cmd)?;
61
+ Ok(())
62
+ }
63
+ }
@@ -1,15 +1,14 @@
1
- use crate::app::Message;
2
- use anyhow::Result;
3
- use std::sync::mpsc;
4
-
5
- #[allow(dead_code)]
6
- pub trait Protocol: Send {
7
- fn run(&mut self) -> Result<()>;
8
- }
9
-
10
- #[allow(dead_code)]
11
- pub struct ProtocolContext {
12
- pub message_tx: mpsc::Sender<Message>,
13
- pub command_rx: mpsc::Receiver<String>,
14
- }
15
-
1
+ use crate::app::Message;
2
+ use anyhow::Result;
3
+ use std::sync::mpsc;
4
+
5
+ #[allow(dead_code)]
6
+ pub trait Protocol: Send {
7
+ fn run(&mut self) -> Result<()>;
8
+ }
9
+
10
+ #[allow(dead_code)]
11
+ pub struct ProtocolContext {
12
+ pub message_tx: mpsc::Sender<Message>,
13
+ pub command_rx: mpsc::Receiver<String>,
14
+ }
@@ -1,32 +1,31 @@
1
- use crate::app::Message;
2
- use crate::io::protocol::Protocol;
3
- use anyhow::Result;
4
- use std::sync::mpsc;
5
-
6
- #[allow(dead_code)]
7
- pub struct StdioProtocol {
8
- #[allow(dead_code)]
9
- message_tx: mpsc::Sender<Message>,
10
- }
11
-
12
- impl StdioProtocol {
13
- #[allow(dead_code)]
14
- pub fn new(message_tx: mpsc::Sender<Message>) -> Result<Self> {
15
- Ok(Self { message_tx })
16
- }
17
- }
18
-
19
- impl Protocol for StdioProtocol {
20
- fn run(&mut self) -> Result<()> {
21
- // DO NOT read from stdin here!
22
- // The TUI needs stdin for keyboard input via crossterm.
23
- // This protocol is a no-op for now.
24
- // In the future, we can use a named pipe or socket for IPC.
25
-
26
- // Just sleep forever to keep the thread alive
27
- loop {
28
- std::thread::sleep(std::time::Duration::from_secs(3600));
29
- }
30
- }
31
- }
32
-
1
+ use crate::app::Message;
2
+ use crate::io::protocol::Protocol;
3
+ use anyhow::Result;
4
+ use std::sync::mpsc;
5
+
6
+ #[allow(dead_code)]
7
+ pub struct StdioProtocol {
8
+ #[allow(dead_code)]
9
+ message_tx: mpsc::Sender<Message>,
10
+ }
11
+
12
+ impl StdioProtocol {
13
+ #[allow(dead_code)]
14
+ pub fn new(message_tx: mpsc::Sender<Message>) -> Result<Self> {
15
+ Ok(Self { message_tx })
16
+ }
17
+ }
18
+
19
+ impl Protocol for StdioProtocol {
20
+ fn run(&mut self) -> Result<()> {
21
+ // DO NOT read from stdin here!
22
+ // The TUI needs stdin for keyboard input via crossterm.
23
+ // This protocol is a no-op for now.
24
+ // In the future, we can use a named pipe or socket for IPC.
25
+
26
+ // Just sleep forever to keep the thread alive
27
+ loop {
28
+ std::thread::sleep(std::time::Duration::from_secs(3600));
29
+ }
30
+ }
31
+ }
@@ -1,32 +1,25 @@
1
- use crate::app::Message;
2
- use crate::io::protocol::Protocol;
3
- use anyhow::Result;
4
- use std::sync::mpsc;
5
-
6
- #[allow(dead_code)]
7
- pub struct WsProtocol {
8
- url: String,
9
- message_tx: mpsc::Sender<Message>,
10
- }
11
-
12
- impl WsProtocol {
13
- #[allow(dead_code)]
14
- pub fn new(
15
- url: String,
16
- message_tx: mpsc::Sender<Message>,
17
- ) -> Result<Self> {
18
- Ok(Self {
19
- url,
20
- message_tx,
21
- })
22
- }
23
- }
24
-
25
- impl Protocol for WsProtocol {
26
- fn run(&mut self) -> Result<()> {
27
- // This will be implemented with tokio runtime
28
- // For now, return error to fallback to stdio
29
- anyhow::bail!("WebSocket not yet implemented, use stdio");
30
- }
31
- }
32
-
1
+ use crate::app::Message;
2
+ use crate::io::protocol::Protocol;
3
+ use anyhow::Result;
4
+ use std::sync::mpsc;
5
+
6
+ #[allow(dead_code)]
7
+ pub struct WsProtocol {
8
+ url: String,
9
+ message_tx: mpsc::Sender<Message>,
10
+ }
11
+
12
+ impl WsProtocol {
13
+ #[allow(dead_code)]
14
+ pub fn new(url: String, message_tx: mpsc::Sender<Message>) -> Result<Self> {
15
+ Ok(Self { url, message_tx })
16
+ }
17
+ }
18
+
19
+ impl Protocol for WsProtocol {
20
+ fn run(&mut self) -> Result<()> {
21
+ // This will be implemented with tokio runtime
22
+ // For now, return error to fallback to stdio
23
+ anyhow::bail!("WebSocket not yet implemented, use stdio");
24
+ }
25
+ }