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,284 +1,340 @@
1
- /// Help popup screen
2
- /// Professional, organized command reference - REDESIGNED
3
-
4
- use ratatui::prelude::*;
5
- use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
6
- use crate::app::AppState;
7
-
8
- // === 4RUNR BRAND COLORS ===
9
- const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
10
- const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
11
- const NEON_GREEN: Color = Color::Rgb(57, 255, 20);
12
- const AMBER_WARN: Color = Color::Rgb(255, 191, 0);
13
- const TEXT_PRIMARY: Color = Color::Rgb(230, 230, 240);
14
- const TEXT_DIM: Color = Color::Rgb(100, 100, 120);
15
- const BG_PANEL: Color = Color::Rgb(18, 18, 25);
16
-
17
- /// Render help popup overlay
18
- pub fn render_help(f: &mut Frame, area: Rect, _state: &AppState) {
19
- // Render background overlay (dimmed)
20
- let overlay = Block::default()
21
- .style(Style::default().bg(Color::Black));
22
- f.render_widget(overlay, area);
23
-
24
- // Calculate popup size (85% width, 90% height, centered)
25
- let popup_width = (area.width * 85 / 100).max(70);
26
- let popup_height = (area.height * 90 / 100).max(25);
27
- let popup_x = (area.width.saturating_sub(popup_width)) / 2;
28
- let popup_y = (area.height.saturating_sub(popup_height)) / 2;
29
-
30
- let popup_area = Rect {
31
- x: popup_x,
32
- y: popup_y,
33
- width: popup_width,
34
- height: popup_height,
35
- };
36
-
37
- // Render help popup
38
- render_help_content(f, popup_area);
39
- }
40
-
41
- fn render_help_content(f: &mut Frame, area: Rect) {
42
- use ratatui::layout::{Constraint, Direction, Layout};
43
-
44
- // Split into header, content, footer
45
- let chunks = Layout::default()
46
- .direction(Direction::Vertical)
47
- .constraints([
48
- Constraint::Length(3), // Header
49
- Constraint::Min(0), // Content
50
- Constraint::Length(3), // Footer
51
- ])
52
- .split(area);
53
-
54
- // === HEADER ===
55
- let header_block = Block::default()
56
- .title(" 📖 4Runr AI Agent OS - Command Reference ")
57
- .title_style(Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD))
58
- .borders(Borders::ALL)
59
- .border_style(Style::default().fg(CYBER_CYAN))
60
- .style(Style::default().bg(BG_PANEL));
61
-
62
- f.render_widget(header_block, chunks[0]);
63
-
64
- // === CONTENT ===
65
- let content_block = Block::default()
66
- .borders(Borders::ALL)
67
- .border_style(Style::default().fg(CYBER_CYAN))
68
- .style(Style::default().bg(BG_PANEL));
69
-
70
- let inner = content_block.inner(chunks[1]);
71
- f.render_widget(content_block, chunks[1]);
72
-
73
- // Build help text - single column, vertical layout
74
- let help_lines = vec![
75
- Line::from(""),
76
- Line::from(vec![
77
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(CYBER_CYAN)),
78
- ]),
79
- Line::from(vec![
80
- Span::styled(" 🧭 NAVIGATION COMMANDS", Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD)),
81
- ]),
82
- Line::from(vec![
83
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(CYBER_CYAN)),
84
- ]),
85
- Line::from(""),
86
- Line::from(vec![
87
- Span::styled(" build", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
88
- ]),
89
- Line::from(vec![
90
- Span::styled(" Open Agent Builder (6-step wizard)", Style::default().fg(TEXT_PRIMARY)),
91
- ]),
92
- Line::from(""),
93
- Line::from(vec![
94
- Span::styled(" runs", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
95
- ]),
96
- Line::from(vec![
97
- Span::styled(" Open Run Manager (list, filter, sort)", Style::default().fg(TEXT_PRIMARY)),
98
- ]),
99
- Line::from(""),
100
- Line::from(vec![
101
- Span::styled(" config, settings", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
102
- ]),
103
- Line::from(vec![
104
- Span::styled(" Open Settings (mode, AI provider)", Style::default().fg(TEXT_PRIMARY)),
105
- ]),
106
- Line::from(""),
107
- Line::from(""),
108
- Line::from(vec![
109
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(BRAND_PURPLE)),
110
- ]),
111
- Line::from(vec![
112
- Span::styled(" 💻 LOCAL COMMANDS", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
113
- ]),
114
- Line::from(vec![
115
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(BRAND_PURPLE)),
116
- ]),
117
- Line::from(""),
118
- Line::from(vec![
119
- Span::styled(" quit, exit", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
120
- ]),
121
- Line::from(vec![
122
- Span::styled(" Exit application", Style::default().fg(TEXT_PRIMARY)),
123
- ]),
124
- Line::from(""),
125
- Line::from(vec![
126
- Span::styled(" clear", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
127
- ]),
128
- Line::from(vec![
129
- Span::styled(" Clear operations log", Style::default().fg(TEXT_PRIMARY)),
130
- ]),
131
- Line::from(""),
132
- Line::from(vec![
133
- Span::styled(" help", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
134
- ]),
135
- Line::from(vec![
136
- Span::styled(" Show this help", Style::default().fg(TEXT_PRIMARY)),
137
- ]),
138
- Line::from(""),
139
- Line::from(vec![
140
- Span::styled(" :perf", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
141
- ]),
142
- Line::from(vec![
143
- Span::styled(" Show performance stats", Style::default().fg(TEXT_PRIMARY)),
144
- ]),
145
- Line::from(""),
146
- Line::from(""),
147
- Line::from(vec![
148
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(AMBER_WARN)),
149
- ]),
150
- Line::from(vec![
151
- Span::styled(" 🌐 WEBSOCKET COMMANDS (requires connection)", Style::default().fg(AMBER_WARN).add_modifier(Modifier::BOLD)),
152
- ]),
153
- Line::from(vec![
154
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(AMBER_WARN)),
155
- ]),
156
- Line::from(""),
157
- Line::from(vec![
158
- Span::styled(" agent.list", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
159
- ]),
160
- Line::from(vec![
161
- Span::styled(" List all agents", Style::default().fg(TEXT_PRIMARY)),
162
- ]),
163
- Line::from(""),
164
- Line::from(vec![
165
- Span::styled(" agent.get", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
166
- ]),
167
- Line::from(vec![
168
- Span::styled(" Get agent details (data: {name})", Style::default().fg(TEXT_PRIMARY)),
169
- ]),
170
- Line::from(""),
171
- Line::from(vec![
172
- Span::styled(" agent.create", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
173
- ]),
174
- Line::from(vec![
175
- Span::styled(" Create agent (use Agent Builder)", Style::default().fg(TEXT_PRIMARY)),
176
- ]),
177
- Line::from(""),
178
- Line::from(vec![
179
- Span::styled(" agent.delete", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
180
- ]),
181
- Line::from(vec![
182
- Span::styled(" Delete agent (data: {name})", Style::default().fg(TEXT_PRIMARY)),
183
- ]),
184
- Line::from(""),
185
- Line::from(vec![
186
- Span::styled(" system.status", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
187
- ]),
188
- Line::from(vec![
189
- Span::styled(" Get system status", Style::default().fg(TEXT_PRIMARY)),
190
- ]),
191
- Line::from(""),
192
- Line::from(vec![
193
- Span::styled(" run.list", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
194
- ]),
195
- Line::from(vec![
196
- Span::styled(" List runs (requires gateway)", Style::default().fg(TEXT_PRIMARY)),
197
- ]),
198
- Line::from(""),
199
- Line::from(vec![
200
- Span::styled(" tool.list", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
201
- ]),
202
- Line::from(vec![
203
- Span::styled(" List available tools", Style::default().fg(TEXT_PRIMARY)),
204
- ]),
205
- Line::from(""),
206
- Line::from(""),
207
- Line::from(vec![
208
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(CYBER_CYAN)),
209
- ]),
210
- Line::from(vec![
211
- Span::styled(" ⌨️ SCREEN CONTROLS", Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD)),
212
- ]),
213
- Line::from(vec![
214
- Span::styled("═══════════════════════════════════════════════════════════════", Style::default().fg(CYBER_CYAN)),
215
- ]),
216
- Line::from(""),
217
- Line::from(vec![
218
- Span::styled(" Agent Builder:", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
219
- ]),
220
- Line::from(vec![
221
- Span::styled(" Enter", Style::default().fg(NEON_GREEN)),
222
- Span::styled(" = Next step | ", Style::default().fg(TEXT_DIM)),
223
- Span::styled("Backspace", Style::default().fg(NEON_GREEN)),
224
- Span::styled(" = Previous | ", Style::default().fg(TEXT_DIM)),
225
- Span::styled("ESC", Style::default().fg(NEON_GREEN)),
226
- Span::styled(" = Cancel", Style::default().fg(TEXT_DIM)),
227
- ]),
228
- Line::from(""),
229
- Line::from(vec![
230
- Span::styled(" Run Manager:", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
231
- ]),
232
- Line::from(vec![
233
- Span::styled(" ↑/↓", Style::default().fg(NEON_GREEN)),
234
- Span::styled(" = Navigate | ", Style::default().fg(TEXT_DIM)),
235
- Span::styled("F", Style::default().fg(NEON_GREEN)),
236
- Span::styled(" = Filter | ", Style::default().fg(TEXT_DIM)),
237
- Span::styled("S", Style::default().fg(NEON_GREEN)),
238
- Span::styled(" = Sort | ", Style::default().fg(TEXT_DIM)),
239
- Span::styled("R", Style::default().fg(NEON_GREEN)),
240
- Span::styled(" = Refresh", Style::default().fg(TEXT_DIM)),
241
- ]),
242
- Line::from(""),
243
- Line::from(vec![
244
- Span::styled(" Settings:", Style::default().fg(BRAND_PURPLE).add_modifier(Modifier::BOLD)),
245
- ]),
246
- Line::from(vec![
247
- Span::styled(" ↑/↓", Style::default().fg(NEON_GREEN)),
248
- Span::styled(" = Navigate | ", Style::default().fg(TEXT_DIM)),
249
- Span::styled("Space", Style::default().fg(NEON_GREEN)),
250
- Span::styled(" = Toggle | ", Style::default().fg(TEXT_DIM)),
251
- Span::styled("Enter", Style::default().fg(NEON_GREEN)),
252
- Span::styled(" = Save", Style::default().fg(TEXT_DIM)),
253
- ]),
254
- Line::from(""),
255
- ];
256
-
257
- f.render_widget(
258
- Paragraph::new(help_lines)
259
- .style(Style::default().bg(BG_PANEL))
260
- .wrap(Wrap { trim: false }),
261
- inner
262
- );
263
-
264
- // === FOOTER ===
265
- let footer_text = Line::from(vec![
266
- Span::styled("Press ", Style::default().fg(TEXT_DIM)),
267
- Span::styled("ESC", Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD)),
268
- Span::styled(" to close", Style::default().fg(TEXT_DIM)),
269
- ]);
270
-
271
- let footer_block = Block::default()
272
- .borders(Borders::ALL)
273
- .border_style(Style::default().fg(CYBER_CYAN))
274
- .style(Style::default().bg(BG_PANEL));
275
-
276
- let footer_inner = footer_block.inner(chunks[2]);
277
- f.render_widget(footer_block, chunks[2]);
278
- f.render_widget(
279
- Paragraph::new(footer_text)
280
- .style(Style::default().bg(BG_PANEL))
281
- .alignment(Alignment::Center),
282
- footer_inner
283
- );
284
- }
1
+ use crate::app::AppState;
2
+ /// Help popup screen
3
+ /// Professional, organized command reference - REDESIGNED
4
+ use ratatui::prelude::*;
5
+ use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
6
+
7
+ // === 4RUNR BRAND COLORS ===
8
+ const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
9
+ const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
10
+ const NEON_GREEN: Color = Color::Rgb(57, 255, 20);
11
+ const AMBER_WARN: Color = Color::Rgb(255, 191, 0);
12
+ const TEXT_PRIMARY: Color = Color::Rgb(230, 230, 240);
13
+ const TEXT_DIM: Color = Color::Rgb(100, 100, 120);
14
+ const BG_PANEL: Color = Color::Rgb(18, 18, 25);
15
+
16
+ /// Render help popup overlay
17
+ pub fn render_help(f: &mut Frame, area: Rect, _state: &AppState) {
18
+ // Render background overlay (dimmed)
19
+ let overlay = Block::default().style(Style::default().bg(Color::Black));
20
+ f.render_widget(overlay, area);
21
+
22
+ // Calculate popup size (85% width, 90% height, centered)
23
+ let popup_width = (area.width * 85 / 100).max(70);
24
+ let popup_height = (area.height * 90 / 100).max(25);
25
+ let popup_x = (area.width.saturating_sub(popup_width)) / 2;
26
+ let popup_y = (area.height.saturating_sub(popup_height)) / 2;
27
+
28
+ let popup_area = Rect {
29
+ x: popup_x,
30
+ y: popup_y,
31
+ width: popup_width,
32
+ height: popup_height,
33
+ };
34
+
35
+ // Render help popup
36
+ render_help_content(f, popup_area);
37
+ }
38
+
39
+ fn render_help_content(f: &mut Frame, area: Rect) {
40
+ use ratatui::layout::{Constraint, Direction, Layout};
41
+
42
+ // Split into header, content, footer
43
+ let chunks = Layout::default()
44
+ .direction(Direction::Vertical)
45
+ .constraints([
46
+ Constraint::Length(3), // Header
47
+ Constraint::Min(0), // Content
48
+ Constraint::Length(3), // Footer
49
+ ])
50
+ .split(area);
51
+
52
+ // === HEADER ===
53
+ let header_block = Block::default()
54
+ .title(" 📖 4Runr AI Agent OS - Command Reference ")
55
+ .title_style(
56
+ Style::default()
57
+ .fg(BRAND_PURPLE)
58
+ .add_modifier(Modifier::BOLD),
59
+ )
60
+ .borders(Borders::ALL)
61
+ .border_style(Style::default().fg(CYBER_CYAN))
62
+ .style(Style::default().bg(BG_PANEL));
63
+
64
+ f.render_widget(header_block, chunks[0]);
65
+
66
+ // === CONTENT ===
67
+ let content_block = Block::default()
68
+ .borders(Borders::ALL)
69
+ .border_style(Style::default().fg(CYBER_CYAN))
70
+ .style(Style::default().bg(BG_PANEL));
71
+
72
+ let inner = content_block.inner(chunks[1]);
73
+ f.render_widget(content_block, chunks[1]);
74
+
75
+ // Build help text - single column, vertical layout
76
+ let help_lines = vec![
77
+ Line::from(""),
78
+ Line::from(vec![Span::styled(
79
+ "═══════════════════════════════════════════════════════════════",
80
+ Style::default().fg(CYBER_CYAN),
81
+ )]),
82
+ Line::from(vec![Span::styled(
83
+ " 🧭 NAVIGATION COMMANDS",
84
+ Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD),
85
+ )]),
86
+ Line::from(vec![Span::styled(
87
+ "═══════════════════════════════════════════════════════════════",
88
+ Style::default().fg(CYBER_CYAN),
89
+ )]),
90
+ Line::from(""),
91
+ Line::from(vec![Span::styled(
92
+ " build",
93
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
94
+ )]),
95
+ Line::from(vec![Span::styled(
96
+ " Open Agent Builder (6-step wizard)",
97
+ Style::default().fg(TEXT_PRIMARY),
98
+ )]),
99
+ Line::from(""),
100
+ Line::from(vec![Span::styled(
101
+ " runs",
102
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
103
+ )]),
104
+ Line::from(vec![Span::styled(
105
+ " Open Run Manager (list, filter, sort)",
106
+ Style::default().fg(TEXT_PRIMARY),
107
+ )]),
108
+ Line::from(""),
109
+ Line::from(vec![Span::styled(
110
+ " config, settings",
111
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
112
+ )]),
113
+ Line::from(vec![Span::styled(
114
+ " Open Settings (mode, AI provider)",
115
+ Style::default().fg(TEXT_PRIMARY),
116
+ )]),
117
+ Line::from(""),
118
+ Line::from(""),
119
+ Line::from(vec![Span::styled(
120
+ "═══════════════════════════════════════════════════════════════",
121
+ Style::default().fg(BRAND_PURPLE),
122
+ )]),
123
+ Line::from(vec![Span::styled(
124
+ " 💻 LOCAL COMMANDS",
125
+ Style::default()
126
+ .fg(BRAND_PURPLE)
127
+ .add_modifier(Modifier::BOLD),
128
+ )]),
129
+ Line::from(vec![Span::styled(
130
+ "═══════════════════════════════════════════════════════════════",
131
+ Style::default().fg(BRAND_PURPLE),
132
+ )]),
133
+ Line::from(""),
134
+ Line::from(vec![Span::styled(
135
+ " quit, exit",
136
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
137
+ )]),
138
+ Line::from(vec![Span::styled(
139
+ " Exit application",
140
+ Style::default().fg(TEXT_PRIMARY),
141
+ )]),
142
+ Line::from(""),
143
+ Line::from(vec![Span::styled(
144
+ " clear",
145
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
146
+ )]),
147
+ Line::from(vec![Span::styled(
148
+ " Clear operations log",
149
+ Style::default().fg(TEXT_PRIMARY),
150
+ )]),
151
+ Line::from(""),
152
+ Line::from(vec![Span::styled(
153
+ " help",
154
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
155
+ )]),
156
+ Line::from(vec![Span::styled(
157
+ " Show this help",
158
+ Style::default().fg(TEXT_PRIMARY),
159
+ )]),
160
+ Line::from(""),
161
+ Line::from(vec![Span::styled(
162
+ " :perf",
163
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
164
+ )]),
165
+ Line::from(vec![Span::styled(
166
+ " Show performance stats",
167
+ Style::default().fg(TEXT_PRIMARY),
168
+ )]),
169
+ Line::from(""),
170
+ Line::from(""),
171
+ Line::from(vec![Span::styled(
172
+ "═══════════════════════════════════════════════════════════════",
173
+ Style::default().fg(AMBER_WARN),
174
+ )]),
175
+ Line::from(vec![Span::styled(
176
+ " 🌐 WEBSOCKET COMMANDS (requires connection)",
177
+ Style::default().fg(AMBER_WARN).add_modifier(Modifier::BOLD),
178
+ )]),
179
+ Line::from(vec![Span::styled(
180
+ "═══════════════════════════════════════════════════════════════",
181
+ Style::default().fg(AMBER_WARN),
182
+ )]),
183
+ Line::from(""),
184
+ Line::from(vec![Span::styled(
185
+ " agent.list",
186
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
187
+ )]),
188
+ Line::from(vec![Span::styled(
189
+ " List all agents",
190
+ Style::default().fg(TEXT_PRIMARY),
191
+ )]),
192
+ Line::from(""),
193
+ Line::from(vec![Span::styled(
194
+ " agent.get",
195
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
196
+ )]),
197
+ Line::from(vec![Span::styled(
198
+ " Get agent details (data: {name})",
199
+ Style::default().fg(TEXT_PRIMARY),
200
+ )]),
201
+ Line::from(""),
202
+ Line::from(vec![Span::styled(
203
+ " agent.create",
204
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
205
+ )]),
206
+ Line::from(vec![Span::styled(
207
+ " Create agent (use Agent Builder)",
208
+ Style::default().fg(TEXT_PRIMARY),
209
+ )]),
210
+ Line::from(""),
211
+ Line::from(vec![Span::styled(
212
+ " agent.delete",
213
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
214
+ )]),
215
+ Line::from(vec![Span::styled(
216
+ " Delete agent (data: {name})",
217
+ Style::default().fg(TEXT_PRIMARY),
218
+ )]),
219
+ Line::from(""),
220
+ Line::from(vec![Span::styled(
221
+ " system.status",
222
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
223
+ )]),
224
+ Line::from(vec![Span::styled(
225
+ " Get system status",
226
+ Style::default().fg(TEXT_PRIMARY),
227
+ )]),
228
+ Line::from(""),
229
+ Line::from(vec![Span::styled(
230
+ " run.list",
231
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
232
+ )]),
233
+ Line::from(vec![Span::styled(
234
+ " List runs (requires gateway)",
235
+ Style::default().fg(TEXT_PRIMARY),
236
+ )]),
237
+ Line::from(""),
238
+ Line::from(vec![Span::styled(
239
+ " tool.list",
240
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
241
+ )]),
242
+ Line::from(vec![Span::styled(
243
+ " List available tools",
244
+ Style::default().fg(TEXT_PRIMARY),
245
+ )]),
246
+ Line::from(""),
247
+ Line::from(""),
248
+ Line::from(vec![Span::styled(
249
+ "═══════════════════════════════════════════════════════════════",
250
+ Style::default().fg(CYBER_CYAN),
251
+ )]),
252
+ Line::from(vec![Span::styled(
253
+ " ⌨️ SCREEN CONTROLS",
254
+ Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD),
255
+ )]),
256
+ Line::from(vec![Span::styled(
257
+ "═══════════════════════════════════════════════════════════════",
258
+ Style::default().fg(CYBER_CYAN),
259
+ )]),
260
+ Line::from(""),
261
+ Line::from(vec![Span::styled(
262
+ " Agent Builder:",
263
+ Style::default()
264
+ .fg(BRAND_PURPLE)
265
+ .add_modifier(Modifier::BOLD),
266
+ )]),
267
+ Line::from(vec![
268
+ Span::styled(" Enter", Style::default().fg(NEON_GREEN)),
269
+ Span::styled(" = Next step | ", Style::default().fg(TEXT_DIM)),
270
+ Span::styled("Backspace", Style::default().fg(NEON_GREEN)),
271
+ Span::styled(" = Previous | ", Style::default().fg(TEXT_DIM)),
272
+ Span::styled("ESC", Style::default().fg(NEON_GREEN)),
273
+ Span::styled(" = Cancel", Style::default().fg(TEXT_DIM)),
274
+ ]),
275
+ Line::from(""),
276
+ Line::from(vec![Span::styled(
277
+ " Run Manager:",
278
+ Style::default()
279
+ .fg(BRAND_PURPLE)
280
+ .add_modifier(Modifier::BOLD),
281
+ )]),
282
+ Line::from(vec![
283
+ Span::styled(" ↑/↓", Style::default().fg(NEON_GREEN)),
284
+ Span::styled(" = Navigate | ", Style::default().fg(TEXT_DIM)),
285
+ Span::styled("F", Style::default().fg(NEON_GREEN)),
286
+ Span::styled(" = Filter | ", Style::default().fg(TEXT_DIM)),
287
+ Span::styled("S", Style::default().fg(NEON_GREEN)),
288
+ Span::styled(" = Sort | ", Style::default().fg(TEXT_DIM)),
289
+ Span::styled("R", Style::default().fg(NEON_GREEN)),
290
+ Span::styled(" = Refresh", Style::default().fg(TEXT_DIM)),
291
+ ]),
292
+ Line::from(""),
293
+ Line::from(vec![Span::styled(
294
+ " Settings:",
295
+ Style::default()
296
+ .fg(BRAND_PURPLE)
297
+ .add_modifier(Modifier::BOLD),
298
+ )]),
299
+ Line::from(vec![
300
+ Span::styled(" ↑/↓", Style::default().fg(NEON_GREEN)),
301
+ Span::styled(" = Navigate | ", Style::default().fg(TEXT_DIM)),
302
+ Span::styled("Space", Style::default().fg(NEON_GREEN)),
303
+ Span::styled(" = Toggle | ", Style::default().fg(TEXT_DIM)),
304
+ Span::styled("Enter", Style::default().fg(NEON_GREEN)),
305
+ Span::styled(" = Save", Style::default().fg(TEXT_DIM)),
306
+ ]),
307
+ Line::from(""),
308
+ ];
309
+
310
+ f.render_widget(
311
+ Paragraph::new(help_lines)
312
+ .style(Style::default().bg(BG_PANEL))
313
+ .wrap(Wrap { trim: false }),
314
+ inner,
315
+ );
316
+
317
+ // === FOOTER ===
318
+ let footer_text = Line::from(vec![
319
+ Span::styled("Press ", Style::default().fg(TEXT_DIM)),
320
+ Span::styled(
321
+ "ESC",
322
+ Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
323
+ ),
324
+ Span::styled(" to close", Style::default().fg(TEXT_DIM)),
325
+ ]);
326
+
327
+ let footer_block = Block::default()
328
+ .borders(Borders::ALL)
329
+ .border_style(Style::default().fg(CYBER_CYAN))
330
+ .style(Style::default().bg(BG_PANEL));
331
+
332
+ let footer_inner = footer_block.inner(chunks[2]);
333
+ f.render_widget(footer_block, chunks[2]);
334
+ f.render_widget(
335
+ Paragraph::new(footer_text)
336
+ .style(Style::default().bg(BG_PANEL))
337
+ .alignment(Alignment::Center),
338
+ footer_inner,
339
+ );
340
+ }