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,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Signal handling for graceful shutdown of Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module provides signal handling functionality to allow users to
|
|
5
|
+
exit Omnimancer gracefully with Ctrl+C, including cancellation of active
|
|
6
|
+
operations and proper resource cleanup.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import signal
|
|
13
|
+
from typing import Set
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SignalHandler:
|
|
19
|
+
"""
|
|
20
|
+
Handles signal-based shutdown for Omnimancer application.
|
|
21
|
+
|
|
22
|
+
This class manages SIGINT (Ctrl+C) and SIGTERM signals to provide
|
|
23
|
+
graceful shutdown functionality including:
|
|
24
|
+
- Cancellation of active operations
|
|
25
|
+
- Cleanup of agent resources
|
|
26
|
+
- Force exit on double Ctrl+C
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, agent_engine=None):
|
|
30
|
+
"""
|
|
31
|
+
Initialize the SignalHandler.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
agent_engine: Optional agent engine instance for cleanup
|
|
35
|
+
"""
|
|
36
|
+
self.agent_engine = agent_engine
|
|
37
|
+
self.shutdown_event = asyncio.Event()
|
|
38
|
+
self.active_operations: Set[asyncio.Task] = set()
|
|
39
|
+
self.shutdown_in_progress = False
|
|
40
|
+
logger.debug("SignalHandler initialized")
|
|
41
|
+
|
|
42
|
+
def setup_signal_handlers(self) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Register SIGINT (Ctrl+C) and SIGTERM handlers.
|
|
45
|
+
|
|
46
|
+
This method sets up the signal handlers that will be called
|
|
47
|
+
when the user presses Ctrl+C or when the process receives
|
|
48
|
+
a SIGTERM signal.
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
signal.signal(signal.SIGINT, self._handle_interrupt)
|
|
52
|
+
signal.signal(signal.SIGTERM, self._handle_interrupt)
|
|
53
|
+
logger.info("Signal handlers registered for SIGINT and SIGTERM")
|
|
54
|
+
except ValueError as e:
|
|
55
|
+
# This can happen if signal handlers are set up on a thread
|
|
56
|
+
# other than the main thread
|
|
57
|
+
logger.warning(f"Failed to register signal handlers: {e}")
|
|
58
|
+
|
|
59
|
+
def _handle_interrupt(self, signum: int, frame) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Handle interrupt signals gracefully.
|
|
62
|
+
|
|
63
|
+
This method is called when SIGINT or SIGTERM is received.
|
|
64
|
+
On the first signal, it initiates graceful shutdown.
|
|
65
|
+
On the second signal, it forces immediate exit.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
signum: Signal number
|
|
69
|
+
frame: Current stack frame
|
|
70
|
+
"""
|
|
71
|
+
signal_name = "SIGINT" if signum == signal.SIGINT else "SIGTERM"
|
|
72
|
+
logger.debug(f"Received {signal_name} signal")
|
|
73
|
+
|
|
74
|
+
if self.shutdown_in_progress:
|
|
75
|
+
# Force exit on second Ctrl+C
|
|
76
|
+
print("\nForce exit requested. Terminating immediately...")
|
|
77
|
+
logger.info("Force exit requested, terminating immediately")
|
|
78
|
+
os._exit(1)
|
|
79
|
+
|
|
80
|
+
self.shutdown_in_progress = True
|
|
81
|
+
print("\nShutdown requested. Canceling operations...")
|
|
82
|
+
logger.info("Graceful shutdown initiated")
|
|
83
|
+
|
|
84
|
+
# Create shutdown task in the event loop
|
|
85
|
+
try:
|
|
86
|
+
loop = asyncio.get_event_loop()
|
|
87
|
+
if loop.is_running():
|
|
88
|
+
loop.create_task(self._graceful_shutdown())
|
|
89
|
+
else:
|
|
90
|
+
logger.warning("Event loop is not running, cannot create shutdown task")
|
|
91
|
+
except RuntimeError:
|
|
92
|
+
# No event loop running, exit immediately
|
|
93
|
+
logger.warning("No event loop available, exiting immediately")
|
|
94
|
+
os._exit(1)
|
|
95
|
+
|
|
96
|
+
async def _graceful_shutdown(self) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Cancel active operations and shutdown gracefully.
|
|
99
|
+
|
|
100
|
+
This method:
|
|
101
|
+
1. Cancels all active operations
|
|
102
|
+
2. Waits for operations to complete (with timeout)
|
|
103
|
+
3. Cleans up agent resources
|
|
104
|
+
4. Sets the shutdown event
|
|
105
|
+
"""
|
|
106
|
+
logger.info("Starting graceful shutdown process")
|
|
107
|
+
|
|
108
|
+
# Cancel all active operations
|
|
109
|
+
cancelled_count = 0
|
|
110
|
+
for task in self.active_operations.copy():
|
|
111
|
+
if not task.done():
|
|
112
|
+
task.cancel()
|
|
113
|
+
cancelled_count += 1
|
|
114
|
+
|
|
115
|
+
if cancelled_count > 0:
|
|
116
|
+
logger.info(f"Cancelled {cancelled_count} active operations")
|
|
117
|
+
|
|
118
|
+
# Wait for operations to complete or timeout
|
|
119
|
+
if self.active_operations:
|
|
120
|
+
print(
|
|
121
|
+
f"Waiting for {len(self.active_operations)} operations to complete..."
|
|
122
|
+
)
|
|
123
|
+
try:
|
|
124
|
+
await asyncio.wait_for(
|
|
125
|
+
asyncio.gather(*self.active_operations, return_exceptions=True),
|
|
126
|
+
timeout=5.0,
|
|
127
|
+
)
|
|
128
|
+
logger.info("All operations completed successfully")
|
|
129
|
+
except asyncio.TimeoutError:
|
|
130
|
+
print("Timeout waiting for operations to complete. Forcing shutdown...")
|
|
131
|
+
logger.warning("Timeout during graceful shutdown, forcing exit")
|
|
132
|
+
|
|
133
|
+
# Cleanup agent resources
|
|
134
|
+
if self.agent_engine and hasattr(self.agent_engine, "cleanup"):
|
|
135
|
+
try:
|
|
136
|
+
await self.agent_engine.cleanup()
|
|
137
|
+
logger.info("Agent engine cleanup completed")
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.error(f"Error during agent engine cleanup: {e}")
|
|
140
|
+
|
|
141
|
+
# Signal shutdown completion
|
|
142
|
+
self.shutdown_event.set()
|
|
143
|
+
logger.info("Graceful shutdown completed")
|
|
144
|
+
|
|
145
|
+
def register_operation(self, task: asyncio.Task) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Register an active operation for tracking.
|
|
148
|
+
|
|
149
|
+
Registered operations will be cancelled during shutdown
|
|
150
|
+
and automatically removed when they complete.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
task: Asyncio task to track
|
|
154
|
+
"""
|
|
155
|
+
if task.done():
|
|
156
|
+
logger.debug("Attempted to register already completed task")
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
self.active_operations.add(task)
|
|
160
|
+
task.add_done_callback(self.active_operations.discard)
|
|
161
|
+
logger.debug(
|
|
162
|
+
f"Registered operation, total active: {len(self.active_operations)}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
async def wait_for_shutdown(self) -> None:
|
|
166
|
+
"""
|
|
167
|
+
Wait for shutdown signal.
|
|
168
|
+
|
|
169
|
+
This method blocks until a shutdown signal is received
|
|
170
|
+
and the graceful shutdown process is complete.
|
|
171
|
+
"""
|
|
172
|
+
logger.debug("Waiting for shutdown signal")
|
|
173
|
+
await self.shutdown_event.wait()
|
|
174
|
+
logger.info("Shutdown signal received")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP (Model Context Protocol) integration for Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module provides MCP server integration capabilities including
|
|
5
|
+
server connection management, tool discovery, and tool execution.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .client import MCPClient
|
|
9
|
+
from .manager import MCPManager
|
|
10
|
+
|
|
11
|
+
__all__ = ["MCPClient", "MCPManager"]
|