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.
- omnimancer/__init__.py +42 -0
- omnimancer/__main__.py +9 -0
- omnimancer/cli/__init__.py +8 -0
- omnimancer/cli/agent_manager.py +826 -0
- omnimancer/cli/agent_wizard.py +944 -0
- omnimancer/cli/approval_formatter.py +734 -0
- omnimancer/cli/approval_integration.py +734 -0
- omnimancer/cli/approval_prompt.py +1286 -0
- omnimancer/cli/batch_approval_display.py +617 -0
- omnimancer/cli/batch_approval_filters.py +729 -0
- omnimancer/cli/batch_operation_monitor.py +775 -0
- omnimancer/cli/commands/performance_cmd.py +624 -0
- omnimancer/cli/commands.py +757 -0
- omnimancer/cli/completion_handler.py +281 -0
- omnimancer/cli/config_setup_wizard.py +783 -0
- omnimancer/cli/dynamic_commands.py +371 -0
- omnimancer/cli/handlers/__init__.py +18 -0
- omnimancer/cli/handlers/agent_handler.py +865 -0
- omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
- omnimancer/cli/handlers/custom_agent_handler.py +352 -0
- omnimancer/cli/handlers/permissions_handler.py +1609 -0
- omnimancer/cli/interface.py +6695 -0
- omnimancer/cli/performance_dashboard.py +612 -0
- omnimancer/core/__init__.py +34 -0
- omnimancer/core/agent/__init__.py +256 -0
- omnimancer/core/agent/agent_config.py +715 -0
- omnimancer/core/agent/agent_switcher.py +668 -0
- omnimancer/core/agent/approval_context.py +460 -0
- omnimancer/core/agent/approval_dialog.py +902 -0
- omnimancer/core/agent/approval_interface.py +628 -0
- omnimancer/core/agent/approval_manager.py +760 -0
- omnimancer/core/agent/cli_integration.py +470 -0
- omnimancer/core/agent/config.py +845 -0
- omnimancer/core/agent/custom_agent_integration.py +654 -0
- omnimancer/core/agent/diff_renderer.py +706 -0
- omnimancer/core/agent/file_content_display.py +503 -0
- omnimancer/core/agent/file_modification_workflow.py +658 -0
- omnimancer/core/agent/file_system_manager.py +1790 -0
- omnimancer/core/agent/input_handler.py +614 -0
- omnimancer/core/agent/metrics_collector.py +771 -0
- omnimancer/core/agent/optimization_engine.py +729 -0
- omnimancer/core/agent/performance_monitor.py +717 -0
- omnimancer/core/agent/persona.py +870 -0
- omnimancer/core/agent/persona_validator.py +672 -0
- omnimancer/core/agent/program_executor.py +748 -0
- omnimancer/core/agent/proposed_changes_integration.py +663 -0
- omnimancer/core/agent/read_before_write_errors.py +492 -0
- omnimancer/core/agent/read_before_write_ui.py +647 -0
- omnimancer/core/agent/rich_renderer.py +763 -0
- omnimancer/core/agent/status_config.py +238 -0
- omnimancer/core/agent/status_core.py +446 -0
- omnimancer/core/agent/status_integrated_engine.py +540 -0
- omnimancer/core/agent/status_manager.py +878 -0
- omnimancer/core/agent/status_ui_components.py +535 -0
- omnimancer/core/agent/template_applicator.py +548 -0
- omnimancer/core/agent/terminal_status_listener.py +394 -0
- omnimancer/core/agent/token_tracker.py +679 -0
- omnimancer/core/agent/types.py +60 -0
- omnimancer/core/agent/web_client.py +745 -0
- omnimancer/core/agent/workflow_orchestrator.py +826 -0
- omnimancer/core/agent_engine.py +1625 -0
- omnimancer/core/agent_mode_manager.py +706 -0
- omnimancer/core/agent_progress_ui.py +545 -0
- omnimancer/core/chat_manager.py +141 -0
- omnimancer/core/config_manager.py +2199 -0
- omnimancer/core/config_migration.py +772 -0
- omnimancer/core/config_provider.py +1974 -0
- omnimancer/core/config_security_validator.py +393 -0
- omnimancer/core/config_validator.py +768 -0
- omnimancer/core/conversation_manager.py +352 -0
- omnimancer/core/engine.py +787 -0
- omnimancer/core/enhanced_input.py +523 -0
- omnimancer/core/env_loader.py +83 -0
- omnimancer/core/fallback_manager.py +568 -0
- omnimancer/core/health_monitor.py +462 -0
- omnimancer/core/history_manager.py +462 -0
- omnimancer/core/mcp_integration_layer.py +878 -0
- omnimancer/core/models.py +1889 -0
- omnimancer/core/provider_capabilities.py +403 -0
- omnimancer/core/provider_initializer.py +450 -0
- omnimancer/core/provider_registry.py +432 -0
- omnimancer/core/security/__init__.py +16 -0
- omnimancer/core/security/approval_workflow.py +406 -0
- omnimancer/core/security/audit_logger.py +511 -0
- omnimancer/core/security/permission_controller.py +511 -0
- omnimancer/core/security/sandbox_manager.py +379 -0
- omnimancer/core/security/security_manager.py +530 -0
- omnimancer/core/setup_wizard.py +345 -0
- omnimancer/core/setup_wizard_core.py +449 -0
- omnimancer/core/setup_wizard_guide_generator.py +376 -0
- omnimancer/core/setup_wizard_provider_setup.py +454 -0
- omnimancer/core/setup_wizard_ui.py +317 -0
- omnimancer/core/setup_wizard_validation.py +371 -0
- omnimancer/core/signal_handler.py +174 -0
- omnimancer/mcp/__init__.py +11 -0
- omnimancer/mcp/client.py +725 -0
- omnimancer/mcp/manager.py +649 -0
- omnimancer/providers/__init__.py +24 -0
- omnimancer/providers/azure.py +608 -0
- omnimancer/providers/base.py +262 -0
- omnimancer/providers/bedrock.py +711 -0
- omnimancer/providers/claude.py +426 -0
- omnimancer/providers/claude_code.py +406 -0
- omnimancer/providers/cohere.py +412 -0
- omnimancer/providers/factory.py +988 -0
- omnimancer/providers/gemini.py +708 -0
- omnimancer/providers/mistral.py +554 -0
- omnimancer/providers/ollama.py +510 -0
- omnimancer/providers/openai.py +362 -0
- omnimancer/providers/openrouter.py +709 -0
- omnimancer/providers/perplexity.py +476 -0
- omnimancer/providers/vertex.py +617 -0
- omnimancer/providers/xai.py +484 -0
- omnimancer/ui/__init__.py +6 -0
- omnimancer/ui/cancellation_handler.py +235 -0
- omnimancer/ui/progress_indicator.py +318 -0
- omnimancer/utils/__init__.py +22 -0
- omnimancer/utils/error_handler.py +589 -0
- omnimancer/utils/errors.py +667 -0
- omnimancer/utils/retry.py +238 -0
- omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
- omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
- omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
- omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
- omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Terminal Status Listener for Omnimancer Agent Status Streaming.
|
|
3
|
+
|
|
4
|
+
This module provides a Rich-based terminal UI listener that displays real-time
|
|
5
|
+
agent status updates in the terminal using the async status stream system.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import time
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Any, Dict, Optional, Set
|
|
13
|
+
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.live import Live
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
|
|
18
|
+
from .status_core import (
|
|
19
|
+
AgentEvent,
|
|
20
|
+
AgentStatus,
|
|
21
|
+
EventType,
|
|
22
|
+
StatusStreamEvent,
|
|
23
|
+
StatusStreamListener,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TerminalStatusListener(StatusStreamListener):
|
|
30
|
+
"""
|
|
31
|
+
Terminal UI listener for agent status updates using Rich library.
|
|
32
|
+
|
|
33
|
+
Displays real-time status updates in a formatted terminal interface
|
|
34
|
+
with live updating components.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
listener_id: str = "terminal_ui",
|
|
40
|
+
event_types: Optional[Set[EventType]] = None,
|
|
41
|
+
console: Optional[Console] = None,
|
|
42
|
+
update_frequency: float = 0.5,
|
|
43
|
+
):
|
|
44
|
+
"""
|
|
45
|
+
Initialize terminal status listener.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
listener_id: Unique identifier for this listener
|
|
49
|
+
event_types: Set of event types to listen for
|
|
50
|
+
console: Rich console instance (optional)
|
|
51
|
+
update_frequency: How often to update the display (seconds)
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(listener_id, event_types)
|
|
54
|
+
|
|
55
|
+
self.console = console or Console()
|
|
56
|
+
self.update_frequency = update_frequency
|
|
57
|
+
|
|
58
|
+
# Status tracking
|
|
59
|
+
self.agent_statuses: Dict[str, AgentStatus] = {}
|
|
60
|
+
self.active_operations: Dict[str, Dict[str, Any]] = {}
|
|
61
|
+
self.recent_events: list = []
|
|
62
|
+
self.max_recent_events = 10
|
|
63
|
+
|
|
64
|
+
# Display state
|
|
65
|
+
self.live_display: Optional[Live] = None
|
|
66
|
+
self.last_update = 0.0
|
|
67
|
+
self.stats = {
|
|
68
|
+
"events_received": 0,
|
|
69
|
+
"operations_tracked": 0,
|
|
70
|
+
"agents_monitored": 0,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async def start_live_display(self) -> None:
|
|
74
|
+
"""Start the live display interface."""
|
|
75
|
+
if self.live_display is None:
|
|
76
|
+
self.live_display = Live(
|
|
77
|
+
self._generate_display(),
|
|
78
|
+
console=self.console,
|
|
79
|
+
refresh_per_second=1 / self.update_frequency,
|
|
80
|
+
auto_refresh=True,
|
|
81
|
+
)
|
|
82
|
+
self.live_display.start()
|
|
83
|
+
logger.info("Terminal status display started")
|
|
84
|
+
|
|
85
|
+
async def stop_live_display(self) -> None:
|
|
86
|
+
"""Stop the live display interface."""
|
|
87
|
+
if self.live_display:
|
|
88
|
+
self.live_display.stop()
|
|
89
|
+
self.live_display = None
|
|
90
|
+
logger.info("Terminal status display stopped")
|
|
91
|
+
|
|
92
|
+
async def _process_event(self, stream_event: StatusStreamEvent) -> None:
|
|
93
|
+
"""Process incoming status stream events."""
|
|
94
|
+
try:
|
|
95
|
+
event = stream_event.event
|
|
96
|
+
self.stats["events_received"] += 1
|
|
97
|
+
|
|
98
|
+
# Update recent events list
|
|
99
|
+
self.recent_events.append(
|
|
100
|
+
{
|
|
101
|
+
"timestamp": event.timestamp,
|
|
102
|
+
"type": event.event_type.value,
|
|
103
|
+
"agent_id": event.agent_id,
|
|
104
|
+
"priority": stream_event.priority.value,
|
|
105
|
+
"data": event.data,
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Keep only recent events
|
|
110
|
+
if len(self.recent_events) > self.max_recent_events:
|
|
111
|
+
self.recent_events.pop(0)
|
|
112
|
+
|
|
113
|
+
# Process specific event types
|
|
114
|
+
await self._handle_specific_event(event)
|
|
115
|
+
|
|
116
|
+
# Update display if enough time has passed
|
|
117
|
+
current_time = time.time()
|
|
118
|
+
if current_time - self.last_update >= self.update_frequency:
|
|
119
|
+
await self._update_display()
|
|
120
|
+
self.last_update = current_time
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
logger.error(f"Error processing event in terminal listener: {e}")
|
|
124
|
+
|
|
125
|
+
async def _handle_specific_event(self, event: AgentEvent) -> None:
|
|
126
|
+
"""Handle specific event types with appropriate updates."""
|
|
127
|
+
try:
|
|
128
|
+
if event.event_type == EventType.AGENT_STATE_CHANGED:
|
|
129
|
+
# Update agent status
|
|
130
|
+
if event.agent_id and "new_status" in event.data:
|
|
131
|
+
try:
|
|
132
|
+
status_str = event.data["new_status"]
|
|
133
|
+
self.agent_statuses[event.agent_id] = AgentStatus(status_str)
|
|
134
|
+
self.stats["agents_monitored"] = len(
|
|
135
|
+
set(self.agent_statuses.keys())
|
|
136
|
+
)
|
|
137
|
+
except ValueError:
|
|
138
|
+
logger.warning(
|
|
139
|
+
f"Invalid agent status: {event.data['new_status']}"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
elif event.event_type == EventType.OPERATION_STARTED:
|
|
143
|
+
# Track new operation
|
|
144
|
+
if event.operation_id:
|
|
145
|
+
self.active_operations[event.operation_id] = {
|
|
146
|
+
"agent_id": event.agent_id,
|
|
147
|
+
"type": event.data.get("operation_type", "unknown"),
|
|
148
|
+
"description": event.data.get("description", "No description"),
|
|
149
|
+
"start_time": event.timestamp,
|
|
150
|
+
"progress": 0.0,
|
|
151
|
+
"status": "running",
|
|
152
|
+
}
|
|
153
|
+
self.stats["operations_tracked"] = len(self.active_operations)
|
|
154
|
+
|
|
155
|
+
elif event.event_type == EventType.OPERATION_PROGRESS:
|
|
156
|
+
# Update operation progress
|
|
157
|
+
if event.operation_id and event.operation_id in self.active_operations:
|
|
158
|
+
self.active_operations[event.operation_id].update(
|
|
159
|
+
{
|
|
160
|
+
"progress": event.data.get("progress", 0.0),
|
|
161
|
+
"description": event.data.get(
|
|
162
|
+
"description",
|
|
163
|
+
self.active_operations[event.operation_id][
|
|
164
|
+
"description"
|
|
165
|
+
],
|
|
166
|
+
),
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
elif event.event_type in [
|
|
171
|
+
EventType.OPERATION_COMPLETED,
|
|
172
|
+
EventType.OPERATION_FAILED,
|
|
173
|
+
EventType.OPERATION_CANCELLED,
|
|
174
|
+
]:
|
|
175
|
+
# Complete operation
|
|
176
|
+
if event.operation_id and event.operation_id in self.active_operations:
|
|
177
|
+
self.active_operations[event.operation_id].update(
|
|
178
|
+
{
|
|
179
|
+
"status": (
|
|
180
|
+
"completed"
|
|
181
|
+
if event.event_type == EventType.OPERATION_COMPLETED
|
|
182
|
+
else "failed"
|
|
183
|
+
),
|
|
184
|
+
"end_time": event.timestamp,
|
|
185
|
+
"progress": (
|
|
186
|
+
100.0
|
|
187
|
+
if event.event_type == EventType.OPERATION_COMPLETED
|
|
188
|
+
else self.active_operations[event.operation_id][
|
|
189
|
+
"progress"
|
|
190
|
+
]
|
|
191
|
+
),
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Remove completed operations after a delay (in a real implementation)
|
|
196
|
+
# For now, we'll keep them for display purposes
|
|
197
|
+
|
|
198
|
+
except Exception as e:
|
|
199
|
+
logger.error(f"Error handling specific event {event.event_type}: {e}")
|
|
200
|
+
|
|
201
|
+
async def _update_display(self) -> None:
|
|
202
|
+
"""Update the live display with current status."""
|
|
203
|
+
if self.live_display:
|
|
204
|
+
try:
|
|
205
|
+
self.live_display.update(self._generate_display())
|
|
206
|
+
except Exception as e:
|
|
207
|
+
logger.error(f"Error updating display: {e}")
|
|
208
|
+
|
|
209
|
+
def _generate_display(self) -> Panel:
|
|
210
|
+
"""Generate the complete display panel."""
|
|
211
|
+
try:
|
|
212
|
+
# Create main layout
|
|
213
|
+
display_content = []
|
|
214
|
+
|
|
215
|
+
# Add system stats
|
|
216
|
+
display_content.append(self._generate_stats_section())
|
|
217
|
+
|
|
218
|
+
# Add agent status section
|
|
219
|
+
if self.agent_statuses:
|
|
220
|
+
display_content.append(self._generate_agents_section())
|
|
221
|
+
|
|
222
|
+
# Add active operations section
|
|
223
|
+
if self.active_operations:
|
|
224
|
+
display_content.append(self._generate_operations_section())
|
|
225
|
+
|
|
226
|
+
# Add recent events section
|
|
227
|
+
if self.recent_events:
|
|
228
|
+
display_content.append(self._generate_events_section())
|
|
229
|
+
|
|
230
|
+
# Combine all sections
|
|
231
|
+
content = "\n\n".join(display_content)
|
|
232
|
+
|
|
233
|
+
return Panel(
|
|
234
|
+
content,
|
|
235
|
+
title="🤖 Agent Status Monitor",
|
|
236
|
+
border_style="blue",
|
|
237
|
+
title_align="left",
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
except Exception as e:
|
|
241
|
+
logger.error(f"Error generating display: {e}")
|
|
242
|
+
return Panel(f"Display Error: {e}", border_style="red")
|
|
243
|
+
|
|
244
|
+
def _generate_stats_section(self) -> str:
|
|
245
|
+
"""Generate system statistics section."""
|
|
246
|
+
return (
|
|
247
|
+
f"[bold]System Statistics[/bold]\n"
|
|
248
|
+
f"Events Received: {self.stats['events_received']}\n"
|
|
249
|
+
f"Active Operations: {len([op for op in self.active_operations.values() if op['status'] == 'running'])}\n"
|
|
250
|
+
f"Agents Monitored: {self.stats['agents_monitored']}\n"
|
|
251
|
+
f"Last Update: {datetime.now().strftime('%H:%M:%S')}"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def _generate_agents_section(self) -> str:
|
|
255
|
+
"""Generate agent status section."""
|
|
256
|
+
content = "[bold]Agent Status[/bold]\n"
|
|
257
|
+
|
|
258
|
+
for agent_id, status in self.agent_statuses.items():
|
|
259
|
+
# Color coding based on status
|
|
260
|
+
if status == AgentStatus.ENABLED:
|
|
261
|
+
color = "green"
|
|
262
|
+
emoji = "🟢"
|
|
263
|
+
elif status == AgentStatus.RUNNING:
|
|
264
|
+
color = "blue"
|
|
265
|
+
emoji = "🔵"
|
|
266
|
+
elif status == AgentStatus.ERROR:
|
|
267
|
+
color = "red"
|
|
268
|
+
emoji = "🔴"
|
|
269
|
+
else:
|
|
270
|
+
color = "yellow"
|
|
271
|
+
emoji = "🟡"
|
|
272
|
+
|
|
273
|
+
content += f"{emoji} [{color}]{agent_id}[/{color}]: {status.value}\n"
|
|
274
|
+
|
|
275
|
+
return content.rstrip()
|
|
276
|
+
|
|
277
|
+
def _generate_operations_section(self) -> str:
|
|
278
|
+
"""Generate active operations section."""
|
|
279
|
+
content = "[bold]Active Operations[/bold]\n"
|
|
280
|
+
|
|
281
|
+
active_ops = [
|
|
282
|
+
op for op in self.active_operations.values() if op["status"] == "running"
|
|
283
|
+
]
|
|
284
|
+
if not active_ops:
|
|
285
|
+
content += "[dim]No active operations[/dim]"
|
|
286
|
+
else:
|
|
287
|
+
for op in active_ops[:5]: # Show max 5 operations
|
|
288
|
+
progress = op["progress"]
|
|
289
|
+
agent_id = op["agent_id"] or "unknown"
|
|
290
|
+
description = (
|
|
291
|
+
op["description"][:50] + "..."
|
|
292
|
+
if len(op["description"]) > 50
|
|
293
|
+
else op["description"]
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Progress bar representation
|
|
297
|
+
bar_width = 20
|
|
298
|
+
filled = int((progress / 100) * bar_width)
|
|
299
|
+
bar = "â–ˆ" * filled + "â–‘" * (bar_width - filled)
|
|
300
|
+
|
|
301
|
+
content += f"[cyan]{agent_id}[/cyan]: {description}\n"
|
|
302
|
+
content += f" [{progress:5.1f}%] {bar} \n"
|
|
303
|
+
|
|
304
|
+
return content.rstrip()
|
|
305
|
+
|
|
306
|
+
def _generate_events_section(self) -> str:
|
|
307
|
+
"""Generate recent events section."""
|
|
308
|
+
content = "[bold]Recent Events[/bold]\n"
|
|
309
|
+
|
|
310
|
+
if not self.recent_events:
|
|
311
|
+
content += "[dim]No recent events[/dim]"
|
|
312
|
+
else:
|
|
313
|
+
for event in self.recent_events[-5:]: # Show last 5 events
|
|
314
|
+
timestamp = event["timestamp"].strftime("%H:%M:%S")
|
|
315
|
+
event_type = event["type"].replace("_", " ").title()
|
|
316
|
+
agent_id = event["agent_id"] or "system"
|
|
317
|
+
priority = event["priority"]
|
|
318
|
+
|
|
319
|
+
# Color coding by priority
|
|
320
|
+
if priority == "critical":
|
|
321
|
+
color = "red"
|
|
322
|
+
elif priority == "high":
|
|
323
|
+
color = "orange"
|
|
324
|
+
elif priority == "normal":
|
|
325
|
+
color = "yellow"
|
|
326
|
+
else:
|
|
327
|
+
color = "dim"
|
|
328
|
+
|
|
329
|
+
content += f"[{color}]{timestamp}[/{color}] [{agent_id}] {event_type}\n"
|
|
330
|
+
|
|
331
|
+
return content.rstrip()
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# Convenience function to create and start a terminal status listener
|
|
335
|
+
async def create_terminal_status_display(
|
|
336
|
+
status_stream: "AsyncStatusStream",
|
|
337
|
+
) -> TerminalStatusListener:
|
|
338
|
+
"""
|
|
339
|
+
Create and start a terminal status display listener.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
status_stream: The status stream to listen to
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
The created and started terminal listener
|
|
346
|
+
"""
|
|
347
|
+
listener = TerminalStatusListener()
|
|
348
|
+
|
|
349
|
+
# Add listener to stream
|
|
350
|
+
await status_stream.add_listener(listener)
|
|
351
|
+
|
|
352
|
+
# Start live display
|
|
353
|
+
await listener.start_live_display()
|
|
354
|
+
|
|
355
|
+
return listener
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
# Example usage function
|
|
359
|
+
async def example_terminal_monitor():
|
|
360
|
+
"""Example of how to set up terminal monitoring."""
|
|
361
|
+
try:
|
|
362
|
+
from .status_manager import get_status_manager
|
|
363
|
+
|
|
364
|
+
# Get status system components
|
|
365
|
+
status_manager = get_status_manager()
|
|
366
|
+
# The unified manager handles both status and streaming
|
|
367
|
+
|
|
368
|
+
# Initialize the unified manager
|
|
369
|
+
await status_manager.initialize()
|
|
370
|
+
|
|
371
|
+
# Create terminal display
|
|
372
|
+
terminal_display = await create_terminal_status_display(status_manager)
|
|
373
|
+
|
|
374
|
+
print("Terminal status monitor running. Press Ctrl+C to stop.")
|
|
375
|
+
|
|
376
|
+
# Keep running until interrupted
|
|
377
|
+
try:
|
|
378
|
+
while True:
|
|
379
|
+
await asyncio.sleep(1)
|
|
380
|
+
except KeyboardInterrupt:
|
|
381
|
+
print("\nShutting down terminal monitor...")
|
|
382
|
+
finally:
|
|
383
|
+
await terminal_display.stop_live_display()
|
|
384
|
+
await status_stream.stop()
|
|
385
|
+
await status_manager.shutdown()
|
|
386
|
+
|
|
387
|
+
except Exception as e:
|
|
388
|
+
logger.error(f"Error in terminal monitor example: {e}")
|
|
389
|
+
raise
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
if __name__ == "__main__":
|
|
393
|
+
# Run the example
|
|
394
|
+
asyncio.run(example_terminal_monitor())
|