omnimancer-cli 0.1.0__py3-none-any.whl

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 (126) hide show
  1. omnimancer/__init__.py +42 -0
  2. omnimancer/__main__.py +9 -0
  3. omnimancer/cli/__init__.py +8 -0
  4. omnimancer/cli/agent_manager.py +826 -0
  5. omnimancer/cli/agent_wizard.py +944 -0
  6. omnimancer/cli/approval_formatter.py +734 -0
  7. omnimancer/cli/approval_integration.py +734 -0
  8. omnimancer/cli/approval_prompt.py +1286 -0
  9. omnimancer/cli/batch_approval_display.py +617 -0
  10. omnimancer/cli/batch_approval_filters.py +729 -0
  11. omnimancer/cli/batch_operation_monitor.py +775 -0
  12. omnimancer/cli/commands/performance_cmd.py +624 -0
  13. omnimancer/cli/commands.py +757 -0
  14. omnimancer/cli/completion_handler.py +281 -0
  15. omnimancer/cli/config_setup_wizard.py +783 -0
  16. omnimancer/cli/dynamic_commands.py +371 -0
  17. omnimancer/cli/handlers/__init__.py +18 -0
  18. omnimancer/cli/handlers/agent_handler.py +865 -0
  19. omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
  20. omnimancer/cli/handlers/custom_agent_handler.py +352 -0
  21. omnimancer/cli/handlers/permissions_handler.py +1609 -0
  22. omnimancer/cli/interface.py +6695 -0
  23. omnimancer/cli/performance_dashboard.py +612 -0
  24. omnimancer/core/__init__.py +34 -0
  25. omnimancer/core/agent/__init__.py +256 -0
  26. omnimancer/core/agent/agent_config.py +715 -0
  27. omnimancer/core/agent/agent_switcher.py +668 -0
  28. omnimancer/core/agent/approval_context.py +460 -0
  29. omnimancer/core/agent/approval_dialog.py +902 -0
  30. omnimancer/core/agent/approval_interface.py +628 -0
  31. omnimancer/core/agent/approval_manager.py +760 -0
  32. omnimancer/core/agent/cli_integration.py +470 -0
  33. omnimancer/core/agent/config.py +845 -0
  34. omnimancer/core/agent/custom_agent_integration.py +654 -0
  35. omnimancer/core/agent/diff_renderer.py +706 -0
  36. omnimancer/core/agent/file_content_display.py +503 -0
  37. omnimancer/core/agent/file_modification_workflow.py +658 -0
  38. omnimancer/core/agent/file_system_manager.py +1790 -0
  39. omnimancer/core/agent/input_handler.py +614 -0
  40. omnimancer/core/agent/metrics_collector.py +771 -0
  41. omnimancer/core/agent/optimization_engine.py +729 -0
  42. omnimancer/core/agent/performance_monitor.py +717 -0
  43. omnimancer/core/agent/persona.py +870 -0
  44. omnimancer/core/agent/persona_validator.py +672 -0
  45. omnimancer/core/agent/program_executor.py +748 -0
  46. omnimancer/core/agent/proposed_changes_integration.py +663 -0
  47. omnimancer/core/agent/read_before_write_errors.py +492 -0
  48. omnimancer/core/agent/read_before_write_ui.py +647 -0
  49. omnimancer/core/agent/rich_renderer.py +763 -0
  50. omnimancer/core/agent/status_config.py +238 -0
  51. omnimancer/core/agent/status_core.py +446 -0
  52. omnimancer/core/agent/status_integrated_engine.py +540 -0
  53. omnimancer/core/agent/status_manager.py +878 -0
  54. omnimancer/core/agent/status_ui_components.py +535 -0
  55. omnimancer/core/agent/template_applicator.py +548 -0
  56. omnimancer/core/agent/terminal_status_listener.py +394 -0
  57. omnimancer/core/agent/token_tracker.py +679 -0
  58. omnimancer/core/agent/types.py +60 -0
  59. omnimancer/core/agent/web_client.py +745 -0
  60. omnimancer/core/agent/workflow_orchestrator.py +826 -0
  61. omnimancer/core/agent_engine.py +1625 -0
  62. omnimancer/core/agent_mode_manager.py +706 -0
  63. omnimancer/core/agent_progress_ui.py +545 -0
  64. omnimancer/core/chat_manager.py +141 -0
  65. omnimancer/core/config_manager.py +2199 -0
  66. omnimancer/core/config_migration.py +772 -0
  67. omnimancer/core/config_provider.py +1974 -0
  68. omnimancer/core/config_security_validator.py +393 -0
  69. omnimancer/core/config_validator.py +768 -0
  70. omnimancer/core/conversation_manager.py +352 -0
  71. omnimancer/core/engine.py +787 -0
  72. omnimancer/core/enhanced_input.py +523 -0
  73. omnimancer/core/env_loader.py +83 -0
  74. omnimancer/core/fallback_manager.py +568 -0
  75. omnimancer/core/health_monitor.py +462 -0
  76. omnimancer/core/history_manager.py +462 -0
  77. omnimancer/core/mcp_integration_layer.py +878 -0
  78. omnimancer/core/models.py +1889 -0
  79. omnimancer/core/provider_capabilities.py +403 -0
  80. omnimancer/core/provider_initializer.py +450 -0
  81. omnimancer/core/provider_registry.py +432 -0
  82. omnimancer/core/security/__init__.py +16 -0
  83. omnimancer/core/security/approval_workflow.py +406 -0
  84. omnimancer/core/security/audit_logger.py +511 -0
  85. omnimancer/core/security/permission_controller.py +511 -0
  86. omnimancer/core/security/sandbox_manager.py +379 -0
  87. omnimancer/core/security/security_manager.py +530 -0
  88. omnimancer/core/setup_wizard.py +345 -0
  89. omnimancer/core/setup_wizard_core.py +449 -0
  90. omnimancer/core/setup_wizard_guide_generator.py +376 -0
  91. omnimancer/core/setup_wizard_provider_setup.py +454 -0
  92. omnimancer/core/setup_wizard_ui.py +317 -0
  93. omnimancer/core/setup_wizard_validation.py +371 -0
  94. omnimancer/core/signal_handler.py +174 -0
  95. omnimancer/mcp/__init__.py +11 -0
  96. omnimancer/mcp/client.py +725 -0
  97. omnimancer/mcp/manager.py +649 -0
  98. omnimancer/providers/__init__.py +24 -0
  99. omnimancer/providers/azure.py +608 -0
  100. omnimancer/providers/base.py +262 -0
  101. omnimancer/providers/bedrock.py +711 -0
  102. omnimancer/providers/claude.py +426 -0
  103. omnimancer/providers/claude_code.py +406 -0
  104. omnimancer/providers/cohere.py +412 -0
  105. omnimancer/providers/factory.py +988 -0
  106. omnimancer/providers/gemini.py +708 -0
  107. omnimancer/providers/mistral.py +554 -0
  108. omnimancer/providers/ollama.py +510 -0
  109. omnimancer/providers/openai.py +362 -0
  110. omnimancer/providers/openrouter.py +709 -0
  111. omnimancer/providers/perplexity.py +476 -0
  112. omnimancer/providers/vertex.py +617 -0
  113. omnimancer/providers/xai.py +484 -0
  114. omnimancer/ui/__init__.py +6 -0
  115. omnimancer/ui/cancellation_handler.py +235 -0
  116. omnimancer/ui/progress_indicator.py +318 -0
  117. omnimancer/utils/__init__.py +22 -0
  118. omnimancer/utils/error_handler.py +589 -0
  119. omnimancer/utils/errors.py +667 -0
  120. omnimancer/utils/retry.py +238 -0
  121. omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
  122. omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
  123. omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
  124. omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
  125. omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
  126. omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,535 @@
1
+ """
2
+ Rich-based Terminal UI Components for Agent Status Display.
3
+
4
+ This module provides reusable Rich UI components for displaying agent status
5
+ information in a comprehensive and user-friendly terminal interface.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Any, Dict, List, Union
10
+
11
+ from rich.console import Group
12
+ from rich.layout import Layout
13
+ from rich.panel import Panel
14
+ from rich.progress import (
15
+ BarColumn,
16
+ Progress,
17
+ SpinnerColumn,
18
+ TextColumn,
19
+ TimeElapsedColumn,
20
+ )
21
+ from rich.rule import Rule
22
+ from rich.table import Table
23
+ from rich.text import Text
24
+ from rich.tree import Tree
25
+
26
+ from .status_core import (
27
+ AgentEvent,
28
+ AgentOperation,
29
+ AgentStatus,
30
+ EventType,
31
+ OperationStatus,
32
+ )
33
+
34
+
35
+ class AgentStatusTable:
36
+ """Rich table component for displaying agent status information."""
37
+
38
+ def __init__(self, title: str = "Agent Status"):
39
+ self.title = title
40
+
41
+ def create_table(
42
+ self,
43
+ agent_statuses: Dict[str, AgentStatus],
44
+ agent_metadata: Dict[str, Dict[str, Any]] = None,
45
+ ) -> Table:
46
+ """
47
+ Create a Rich table displaying agent statuses.
48
+
49
+ Args:
50
+ agent_statuses: Dictionary of agent IDs to their current status
51
+ agent_metadata: Optional metadata for each agent
52
+
53
+ Returns:
54
+ Rich Table object
55
+ """
56
+ table = Table(title=self.title, show_header=True, header_style="bold magenta")
57
+
58
+ table.add_column("Agent ID", style="cyan", width=12)
59
+ table.add_column("Status", style="bold", width=12)
60
+ table.add_column("State", width=15)
61
+ table.add_column("Last Update", style="dim", width=12)
62
+ table.add_column("Operations", justify="right", width=10)
63
+
64
+ agent_metadata = agent_metadata or {}
65
+
66
+ for agent_id, status in agent_statuses.items():
67
+ metadata = agent_metadata.get(agent_id, {})
68
+
69
+ # Status with emoji and color
70
+ status_display = self._format_agent_status(status)
71
+
72
+ # State information
73
+ state = metadata.get("state", "Unknown")
74
+
75
+ # Last update time
76
+ last_update = metadata.get("last_update", datetime.now())
77
+ if isinstance(last_update, datetime):
78
+ time_str = last_update.strftime("%H:%M:%S")
79
+ else:
80
+ time_str = str(last_update)
81
+
82
+ # Active operations count
83
+ operations_count = metadata.get("active_operations", 0)
84
+
85
+ table.add_row(
86
+ agent_id,
87
+ status_display,
88
+ state,
89
+ time_str,
90
+ str(operations_count),
91
+ )
92
+
93
+ return table
94
+
95
+ def _format_agent_status(self, status: AgentStatus) -> Text:
96
+ """Format agent status with appropriate color and emoji."""
97
+ status_mapping = {
98
+ AgentStatus.ENABLED: ("🟢", "green", "Enabled"),
99
+ AgentStatus.DISABLED: ("🔴", "red", "Disabled"),
100
+ AgentStatus.RUNNING: ("🔵", "blue", "Running"),
101
+ AgentStatus.PAUSED: ("🟡", "yellow", "Paused"),
102
+ AgentStatus.ERROR: ("❌", "red", "Error"),
103
+ AgentStatus.INITIALIZING: ("🔄", "blue", "Starting"),
104
+ AgentStatus.SHUTTING_DOWN: ("⏹️", "orange", "Stopping"),
105
+ }
106
+
107
+ emoji, color, text = status_mapping.get(status, ("❓", "white", status.value))
108
+
109
+ return Text(f"{emoji} {text}", style=color)
110
+
111
+
112
+ class OperationProgress:
113
+ """Rich progress component for displaying operation progress."""
114
+
115
+ def __init__(self):
116
+ self.progress = Progress(
117
+ SpinnerColumn(),
118
+ TextColumn("[progress.description]{task.description}"),
119
+ BarColumn(bar_width=None),
120
+ "[progress.percentage]{task.percentage:>3.1f}%",
121
+ TimeElapsedColumn(),
122
+ console=None,
123
+ auto_refresh=True,
124
+ refresh_per_second=2,
125
+ )
126
+
127
+ def create_progress_display(
128
+ self, operations: List[AgentOperation]
129
+ ) -> Union[Progress, Text]:
130
+ """
131
+ Create a progress display for active operations.
132
+
133
+ Args:
134
+ operations: List of operations to display
135
+
136
+ Returns:
137
+ Progress widget or Text if no operations
138
+ """
139
+ if not operations:
140
+ return Text("No active operations", style="dim")
141
+
142
+ # Clear existing tasks
143
+ for task_id in list(self.progress.task_ids):
144
+ self.progress.remove_task(task_id)
145
+
146
+ # Add current operations
147
+ for operation in operations:
148
+ if operation.is_active:
149
+ description = (
150
+ f"[{operation.agent_id or 'system'}] {operation.description[:40]}"
151
+ )
152
+ if len(operation.description) > 40:
153
+ description += "..."
154
+
155
+ self.progress.add_task(
156
+ description=description,
157
+ total=100,
158
+ completed=operation.progress_percentage,
159
+ )
160
+
161
+ return (
162
+ self.progress
163
+ if self.progress.task_ids
164
+ else Text("No active operations", style="dim")
165
+ )
166
+
167
+
168
+ class EventLogPanel:
169
+ """Rich panel component for displaying recent events."""
170
+
171
+ def __init__(self, max_events: int = 10):
172
+ self.max_events = max_events
173
+
174
+ def create_event_log(
175
+ self, events: List[AgentEvent], title: str = "Recent Events"
176
+ ) -> Panel:
177
+ """
178
+ Create a panel displaying recent events.
179
+
180
+ Args:
181
+ events: List of recent events
182
+ title: Panel title
183
+
184
+ Returns:
185
+ Rich Panel object
186
+ """
187
+ if not events:
188
+ content = Text("No recent events", style="dim")
189
+ else:
190
+ # Take only the most recent events
191
+ recent_events = (
192
+ events[-self.max_events :] if len(events) > self.max_events else events
193
+ )
194
+
195
+ lines = []
196
+ for event in recent_events:
197
+ # Format timestamp
198
+ timestamp = event.timestamp.strftime("%H:%M:%S.%f")[
199
+ :-3
200
+ ] # Include milliseconds
201
+
202
+ # Format event type with color
203
+ event_display = self._format_event_type(event.event_type)
204
+
205
+ # Agent ID
206
+ agent_id = event.agent_id or "system"
207
+
208
+ # Event description based on type and data
209
+ description = self._get_event_description(event)
210
+
211
+ # Combine into a line
212
+ line = (
213
+ f"[dim]{timestamp}[/dim] [{agent_id}] {event_display} {description}"
214
+ )
215
+ lines.append(line)
216
+
217
+ content = "\n".join(lines)
218
+
219
+ return Panel(content, title=title, border_style="yellow", padding=(0, 1))
220
+
221
+ def _format_event_type(self, event_type: EventType) -> Text:
222
+ """Format event type with appropriate color."""
223
+ type_colors = {
224
+ EventType.AGENT_STATE_CHANGED: ("blue", "📝"),
225
+ EventType.OPERATION_STARTED: ("green", "▶️"),
226
+ EventType.OPERATION_PROGRESS: ("cyan", "📊"),
227
+ EventType.OPERATION_COMPLETED: ("green", "✅"),
228
+ EventType.OPERATION_FAILED: ("red", "❌"),
229
+ EventType.OPERATION_CANCELLED: ("yellow", "⏹️"),
230
+ EventType.ERROR_OCCURRED: ("red", "🚨"),
231
+ EventType.APPROVAL_REQUESTED: ("magenta", "🔐"),
232
+ EventType.APPROVAL_GRANTED: ("green", "🔓"),
233
+ EventType.APPROVAL_DENIED: ("red", "🔒"),
234
+ }
235
+
236
+ color, emoji = type_colors.get(event_type, ("white", "📌"))
237
+ return Text(f"{emoji}", style=color)
238
+
239
+ def _get_event_description(self, event: AgentEvent) -> str:
240
+ """Generate event description based on event type and data."""
241
+ if event.event_type == EventType.AGENT_STATE_CHANGED:
242
+ old_status = event.data.get("old_status", "unknown")
243
+ new_status = event.data.get("new_status", "unknown")
244
+ return f"Status: {old_status} → {new_status}"
245
+
246
+ elif event.event_type == EventType.OPERATION_STARTED:
247
+ op_type = event.data.get("operation_type", "unknown")
248
+ description = event.data.get("description", "No description")
249
+ return (
250
+ f"{op_type}: {description[:30]}{'...' if len(description) > 30 else ''}"
251
+ )
252
+
253
+ elif event.event_type == EventType.OPERATION_PROGRESS:
254
+ progress = event.data.get("progress", 0)
255
+ return f"Progress: {progress:.1f}%"
256
+
257
+ elif event.event_type == EventType.OPERATION_COMPLETED:
258
+ duration = event.data.get("duration", 0)
259
+ return f"Completed in {duration:.2f}s"
260
+
261
+ elif event.event_type == EventType.OPERATION_FAILED:
262
+ error = event.data.get("error", "Unknown error")
263
+ return f"Failed: {error[:30]}{'...' if len(error) > 30 else ''}"
264
+
265
+ elif event.event_type == EventType.ERROR_OCCURRED:
266
+ error = event.data.get("error", "Unknown error")
267
+ return f"Error: {error[:30]}{'...' if len(error) > 30 else ''}"
268
+
269
+ else:
270
+ return event.event_type.value.replace("_", " ").title()
271
+
272
+
273
+ class SystemStatsPanel:
274
+ """Rich panel component for displaying system statistics."""
275
+
276
+ def create_stats_panel(
277
+ self, stats: Dict[str, Any], title: str = "System Statistics"
278
+ ) -> Panel:
279
+ """
280
+ Create a panel displaying system statistics.
281
+
282
+ Args:
283
+ stats: Dictionary of statistics
284
+ title: Panel title
285
+
286
+ Returns:
287
+ Rich Panel object
288
+ """
289
+ # Create a table for stats
290
+ table = Table(show_header=False, show_edge=False, padding=(0, 2))
291
+ table.add_column("Metric", style="bold", width=20)
292
+ table.add_column("Value", justify="right", width=10)
293
+
294
+ # Add key statistics
295
+ key_stats = [
296
+ ("Active Agents", stats.get("enabled_agents", 0)),
297
+ ("Total Agents", stats.get("total_agents", 0)),
298
+ ("Operations", f"{stats.get('operations_started', 0)}"),
299
+ ("Completed", f"{stats.get('operations_completed', 0)}"),
300
+ ("Failed", f"{stats.get('operations_failed', 0)}"),
301
+ ("Events", f"{stats.get('events_emitted', 0)}"),
302
+ ("Listeners", f"{stats.get('event_listeners', 0)}"),
303
+ ]
304
+
305
+ for metric, value in key_stats:
306
+ # Color coding for certain metrics
307
+ if metric == "Failed" and int(str(value)) > 0:
308
+ value_style = "red"
309
+ elif metric in ["Completed", "Active Agents"] and int(str(value)) > 0:
310
+ value_style = "green"
311
+ else:
312
+ value_style = "white"
313
+
314
+ table.add_row(metric, Text(str(value), style=value_style))
315
+
316
+ return Panel(table, title=title, border_style="blue", padding=(0, 1))
317
+
318
+
319
+ class OperationDetailsTree:
320
+ """Rich tree component for displaying operation hierarchy."""
321
+
322
+ def create_operation_tree(
323
+ self, operations: List[AgentOperation], title: str = "Operations"
324
+ ) -> Panel:
325
+ """
326
+ Create a tree view of operations grouped by agent.
327
+
328
+ Args:
329
+ operations: List of operations to display
330
+ title: Tree title
331
+
332
+ Returns:
333
+ Rich Panel containing the tree
334
+ """
335
+ if not operations:
336
+ return Panel(
337
+ Text("No operations to display", style="dim"),
338
+ title=title,
339
+ border_style="green",
340
+ )
341
+
342
+ # Group operations by agent
343
+ by_agent: Dict[str, List[AgentOperation]] = {}
344
+ for operation in operations:
345
+ agent_id = operation.agent_id or "system"
346
+ if agent_id not in by_agent:
347
+ by_agent[agent_id] = []
348
+ by_agent[agent_id].append(operation)
349
+
350
+ # Create tree
351
+ tree = Tree(f"[bold]{title}[/bold]")
352
+
353
+ for agent_id, agent_operations in by_agent.items():
354
+ # Add agent branch
355
+ agent_branch = tree.add(
356
+ f"[cyan]{agent_id}[/cyan] ({len(agent_operations)} operations)"
357
+ )
358
+
359
+ for operation in agent_operations[:5]: # Limit to 5 operations per agent
360
+ # Format operation
361
+ status_emoji = {
362
+ OperationStatus.PENDING: "⏳",
363
+ OperationStatus.RUNNING: "▶️",
364
+ OperationStatus.COMPLETED: "✅",
365
+ OperationStatus.FAILED: "❌",
366
+ OperationStatus.CANCELLED: "⏹️",
367
+ OperationStatus.WAITING_APPROVAL: "🔐",
368
+ }.get(operation.status, "❓")
369
+
370
+ duration_str = ""
371
+ if operation.duration:
372
+ duration_str = f" ({operation.duration.total_seconds():.1f}s)"
373
+
374
+ operation_text = (
375
+ f"{status_emoji} {operation.operation_type.value} "
376
+ f"[{operation.progress_percentage:.0f}%]{duration_str}"
377
+ )
378
+
379
+ if operation.description:
380
+ operation_text += f"\n {operation.description[:50]}"
381
+ if len(operation.description) > 50:
382
+ operation_text += "..."
383
+
384
+ agent_branch.add(operation_text)
385
+
386
+ if len(agent_operations) > 5:
387
+ agent_branch.add(
388
+ f"[dim]... and {len(agent_operations) - 5} more operations[/dim]"
389
+ )
390
+
391
+ return Panel(tree, title=title, border_style="green")
392
+
393
+
394
+ class ComprehensiveStatusDisplay:
395
+ """
396
+ Comprehensive status display combining all UI components.
397
+
398
+ Creates a rich, multi-panel display showing all aspects of agent status.
399
+ """
400
+
401
+ def __init__(self):
402
+ self.agent_table = AgentStatusTable()
403
+ self.operation_progress = OperationProgress()
404
+ self.event_log = EventLogPanel()
405
+ self.stats_panel = SystemStatsPanel()
406
+ self.operation_tree = OperationDetailsTree()
407
+
408
+ def create_comprehensive_display(
409
+ self,
410
+ agent_statuses: Dict[str, AgentStatus],
411
+ agent_metadata: Dict[str, Dict[str, Any]],
412
+ active_operations: List[AgentOperation],
413
+ recent_events: List[AgentEvent],
414
+ system_stats: Dict[str, Any],
415
+ ) -> Layout:
416
+ """
417
+ Create a comprehensive status display with all components.
418
+
419
+ Args:
420
+ agent_statuses: Current agent statuses
421
+ agent_metadata: Agent metadata
422
+ active_operations: Active operations
423
+ recent_events: Recent events
424
+ system_stats: System statistics
425
+
426
+ Returns:
427
+ Rich Layout object
428
+ """
429
+ # Create layout
430
+ layout = Layout()
431
+
432
+ # Split into main sections
433
+ layout.split_row(Layout(name="left"), Layout(name="right"))
434
+
435
+ # Left side: Agent info and operations
436
+ layout["left"].split_column(
437
+ Layout(
438
+ self.agent_table.create_table(agent_statuses, agent_metadata),
439
+ name="agents",
440
+ ),
441
+ Layout(
442
+ self.operation_progress.create_progress_display(active_operations),
443
+ name="progress",
444
+ ),
445
+ )
446
+
447
+ # Right side: Events, stats, and operation tree
448
+ layout["right"].split_column(
449
+ Layout(self.event_log.create_event_log(recent_events), name="events"),
450
+ Layout(name="bottom_right"),
451
+ )
452
+
453
+ # Split bottom right into stats and tree
454
+ layout["bottom_right"].split_row(
455
+ Layout(self.stats_panel.create_stats_panel(system_stats), name="stats"),
456
+ Layout(
457
+ self.operation_tree.create_operation_tree(active_operations),
458
+ name="tree",
459
+ ),
460
+ )
461
+
462
+ return layout
463
+
464
+ def create_simple_display(
465
+ self,
466
+ agent_statuses: Dict[str, AgentStatus],
467
+ recent_events: List[AgentEvent],
468
+ system_stats: Dict[str, Any],
469
+ ) -> Group:
470
+ """
471
+ Create a simpler status display for constrained terminals.
472
+
473
+ Args:
474
+ agent_statuses: Current agent statuses
475
+ recent_events: Recent events
476
+ system_stats: System statistics
477
+
478
+ Returns:
479
+ Rich Group object
480
+ """
481
+ components = [
482
+ self.stats_panel.create_stats_panel(system_stats, "📊 System Status"),
483
+ Rule(),
484
+ self.agent_table.create_table(agent_statuses),
485
+ Rule(),
486
+ self.event_log.create_event_log(recent_events, "📝 Recent Activity"),
487
+ ]
488
+
489
+ return Group(*components)
490
+
491
+
492
+ # Utility functions for creating common display components
493
+ def create_agent_status_summary(
494
+ agent_statuses: Dict[str, AgentStatus],
495
+ ) -> Text:
496
+ """Create a brief text summary of agent statuses."""
497
+ if not agent_statuses:
498
+ return Text("No agents available", style="dim")
499
+
500
+ enabled = sum(
501
+ 1 for status in agent_statuses.values() if status == AgentStatus.ENABLED
502
+ )
503
+ total = len(agent_statuses)
504
+
505
+ summary = f"Agents: {enabled}/{total} enabled"
506
+
507
+ if enabled > 0:
508
+ style = "green"
509
+ elif total > 0:
510
+ style = "yellow"
511
+ else:
512
+ style = "red"
513
+
514
+ return Text(summary, style=style)
515
+
516
+
517
+ def create_operation_summary(operations: List[AgentOperation]) -> Text:
518
+ """Create a brief text summary of operations."""
519
+ if not operations:
520
+ return Text("No active operations", style="dim")
521
+
522
+ active = sum(1 for op in operations if op.is_active)
523
+ completed = sum(1 for op in operations if op.status == OperationStatus.COMPLETED)
524
+ failed = sum(1 for op in operations if op.status == OperationStatus.FAILED)
525
+
526
+ summary = f"Ops: {active} active, {completed} done, {failed} failed"
527
+
528
+ if failed > 0:
529
+ style = "red"
530
+ elif active > 0:
531
+ style = "blue"
532
+ else:
533
+ style = "green"
534
+
535
+ return Text(summary, style=style)