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,470 @@
1
+ """
2
+ CLI Integration for Status-Enhanced Agent System.
3
+
4
+ This module provides integration between the CLI interface and the
5
+ status-enhanced agent engine, enabling status display in CLI commands.
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ from typing import Any, Callable, Dict, List, Optional
11
+
12
+ from rich.console import Console
13
+ from rich.live import Live
14
+ from rich.panel import Panel
15
+
16
+ from ..config_manager import ConfigManager
17
+ from .status_integrated_engine import (
18
+ StatusIntegratedAgentEngine,
19
+ create_status_integrated_engine,
20
+ )
21
+ from .status_ui_components import (
22
+ ComprehensiveStatusDisplay,
23
+ )
24
+ from .terminal_status_listener import TerminalStatusListener
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class CLIStatusIntegration:
30
+ """
31
+ Integration layer between CLI and status-enhanced agent system.
32
+
33
+ Provides methods for CLI commands to interact with and display
34
+ agent status information.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ engine: StatusIntegratedAgentEngine,
40
+ console: Optional[Console] = None,
41
+ ):
42
+ """
43
+ Initialize CLI status integration.
44
+
45
+ Args:
46
+ engine: Status-integrated agent engine
47
+ console: Rich console for output
48
+ """
49
+ self.engine = engine
50
+ self.console = console or Console()
51
+ self.status_listener: Optional[TerminalStatusListener] = None
52
+ self.live_display: Optional[Live] = None
53
+ self.ui_display = ComprehensiveStatusDisplay()
54
+
55
+ async def start_live_status_display(self) -> bool:
56
+ """
57
+ Start live status display in the terminal.
58
+
59
+ Returns:
60
+ True if display started successfully
61
+ """
62
+ try:
63
+ if not self.engine.is_status_display_enabled():
64
+ self.console.print("[yellow]Status display is disabled[/yellow]")
65
+ return False
66
+
67
+ # Ensure status monitoring is started
68
+ await self.engine.start_status_monitoring()
69
+
70
+ # Create terminal listener if not exists
71
+ if not self.status_listener:
72
+ self.status_listener = TerminalStatusListener(
73
+ "cli_status_display", console=self.console
74
+ )
75
+
76
+ # Add to status manager (which handles streaming)
77
+ await self.engine.status_manager.add_listener(self.status_listener)
78
+
79
+ # Start live display
80
+ await self.status_listener.start_live_display()
81
+
82
+ self.console.print("[green]✅ Live status display started[/green]")
83
+ return True
84
+
85
+ except Exception as e:
86
+ logger.error(f"Failed to start live status display: {e}")
87
+ self.console.print(f"[red]❌ Failed to start status display: {e}[/red]")
88
+ return False
89
+
90
+ async def stop_live_status_display(self) -> bool:
91
+ """
92
+ Stop live status display.
93
+
94
+ Returns:
95
+ True if display stopped successfully
96
+ """
97
+ try:
98
+ if self.status_listener:
99
+ await self.status_listener.stop_live_display()
100
+
101
+ # Remove from status manager
102
+ await self.engine.status_manager.remove_listener(
103
+ self.status_listener.listener_id
104
+ )
105
+
106
+ self.status_listener = None
107
+
108
+ self.console.print("[yellow]⏹️ Live status display stopped[/yellow]")
109
+ return True
110
+
111
+ except Exception as e:
112
+ logger.error(f"Failed to stop live status display: {e}")
113
+ self.console.print(f"[red]❌ Failed to stop status display: {e}[/red]")
114
+ return False
115
+
116
+ async def show_status_snapshot(self, detailed: bool = False) -> None:
117
+ """
118
+ Show a snapshot of current status.
119
+
120
+ Args:
121
+ detailed: Whether to show detailed information
122
+ """
123
+ try:
124
+ if not self.engine.is_status_display_enabled():
125
+ self.console.print("[yellow]Status display is disabled[/yellow]")
126
+ return
127
+
128
+ # Get status data
129
+ status_summary = await self.engine.get_status_summary()
130
+
131
+ if "error" in status_summary:
132
+ self.console.print(
133
+ f"[red]❌ Error getting status: {status_summary['error']}[/red]"
134
+ )
135
+ return
136
+
137
+ # Display basic info
138
+ status_summary.get("status", "unknown")
139
+ status_summary.get("active_operations_count", 0)
140
+
141
+ # Create status display
142
+ if detailed:
143
+ self._show_detailed_status(status_summary)
144
+ else:
145
+ self._show_basic_status(status_summary)
146
+
147
+ except Exception as e:
148
+ logger.error(f"Failed to show status snapshot: {e}")
149
+ self.console.print(f"[red]❌ Failed to get status: {e}[/red]")
150
+
151
+ def _show_basic_status(self, status_summary: Dict[str, Any]) -> None:
152
+ """Show basic status information."""
153
+ agent_id = status_summary.get("agent_id", "unknown")
154
+ status = status_summary.get("status", "unknown")
155
+ active_ops = status_summary.get("active_operations_count", 0)
156
+
157
+ # Status color coding
158
+ if status == "enabled":
159
+ status_color = "green"
160
+ status_emoji = "🟢"
161
+ elif status == "running":
162
+ status_color = "blue"
163
+ status_emoji = "🔵"
164
+ elif status == "error":
165
+ status_color = "red"
166
+ status_emoji = "🔴"
167
+ else:
168
+ status_color = "yellow"
169
+ status_emoji = "🟡"
170
+
171
+ content = f"[bold]Agent Status[/bold]\n\n"
172
+ content += f"Agent ID: [cyan]{agent_id}[/cyan]\n"
173
+ content += f"Status: [{status_color}]{status_emoji} {status.title()}[/{status_color}]\n"
174
+ content += f"Active Operations: [blue]{active_ops}[/blue]\n"
175
+
176
+ if status_summary.get("status_stream_running", False):
177
+ content += f"Status Stream: [green]🟢 Running[/green]\n"
178
+ else:
179
+ content += f"Status Stream: [red]🔴 Stopped[/red]\n"
180
+
181
+ self.console.print(Panel(content, title="📊 Agent Status", border_style="blue"))
182
+
183
+ def _show_detailed_status(self, status_summary: Dict[str, Any]) -> None:
184
+ """Show detailed status information."""
185
+ # Basic info
186
+ self._show_basic_status(status_summary)
187
+
188
+ # Active operations
189
+ active_operations = status_summary.get("active_operations", [])
190
+ if active_operations:
191
+ self.console.print("\n[bold]Active Operations:[/bold]")
192
+
193
+ for op in active_operations:
194
+ op_type = op.get("type", "unknown")
195
+ description = op.get("description", "No description")
196
+ progress = op.get("progress", 0)
197
+ duration = op.get("duration", 0)
198
+
199
+ # Progress bar
200
+ bar_width = 20
201
+ filled = int((progress / 100) * bar_width)
202
+ bar = "█" * filled + "░" * (bar_width - filled)
203
+
204
+ op_info = f" [{progress:5.1f}%] {bar} {op_type}: {description}"
205
+ if duration > 0:
206
+ op_info += f" ({duration:.1f}s)"
207
+
208
+ self.console.print(op_info)
209
+
210
+ # System stats
211
+ system_stats = status_summary.get("system_stats", {})
212
+ if system_stats:
213
+ self.console.print(f"\n[bold]System Statistics:[/bold]")
214
+ self.console.print(
215
+ f" Events Emitted: {system_stats.get('events_emitted', 0)}"
216
+ )
217
+ self.console.print(
218
+ f" Operations Started: {system_stats.get('operations_started', 0)}"
219
+ )
220
+ self.console.print(
221
+ f" Operations Completed: {system_stats.get('operations_completed', 0)}"
222
+ )
223
+ self.console.print(
224
+ f" Operations Failed: {system_stats.get('operations_failed', 0)}"
225
+ )
226
+
227
+ async def execute_with_status_display(
228
+ self, operation_func: Callable, *args, **kwargs
229
+ ) -> Any:
230
+ """
231
+ Execute a function while displaying status updates.
232
+
233
+ Args:
234
+ operation_func: Function to execute
235
+ *args, **kwargs: Arguments for the function
236
+
237
+ Returns:
238
+ Result of the function
239
+ """
240
+ try:
241
+ # Start live display if not already running
242
+ display_started = False
243
+ if not self.status_listener:
244
+ display_started = await self.start_live_status_display()
245
+
246
+ # Execute the operation
247
+ if asyncio.iscoroutinefunction(operation_func):
248
+ result = await operation_func(*args, **kwargs)
249
+ else:
250
+ result = operation_func(*args, **kwargs)
251
+
252
+ # Stop display if we started it
253
+ if display_started:
254
+ await self.stop_live_status_display()
255
+
256
+ return result
257
+
258
+ except Exception:
259
+ # Stop display if we started it
260
+ if display_started and self.status_listener:
261
+ await self.stop_live_status_display()
262
+ raise
263
+
264
+ def is_live_display_running(self) -> bool:
265
+ """Check if live display is currently running."""
266
+ return (
267
+ self.status_listener is not None
268
+ and hasattr(self.status_listener, "live_display")
269
+ and self.status_listener.live_display is not None
270
+ )
271
+
272
+ async def get_quick_status(self) -> str:
273
+ """Get a quick one-line status summary."""
274
+ try:
275
+ if not self.engine.is_status_display_enabled():
276
+ return "Status display disabled"
277
+
278
+ status_summary = await self.engine.get_status_summary()
279
+
280
+ if "error" in status_summary:
281
+ return f"Status error: {status_summary['error']}"
282
+
283
+ agent_id = status_summary.get("agent_id", "agent")
284
+ status = status_summary.get("status", "unknown")
285
+ active_ops = status_summary.get("active_operations_count", 0)
286
+
287
+ return f"{agent_id}: {status} ({active_ops} active operations)"
288
+
289
+ except Exception as e:
290
+ return f"Status unavailable: {e}"
291
+
292
+
293
+ class CLIStatusCommand:
294
+ """
295
+ CLI command handler for status-related operations.
296
+
297
+ Provides subcommands for managing agent status display.
298
+ """
299
+
300
+ def __init__(self, integration: CLIStatusIntegration):
301
+ """
302
+ Initialize status command handler.
303
+
304
+ Args:
305
+ integration: CLI status integration instance
306
+ """
307
+ self.integration = integration
308
+ self.console = integration.console
309
+
310
+ async def handle_command(self, args: List[str]) -> None:
311
+ """
312
+ Handle status command with subcommands.
313
+
314
+ Args:
315
+ args: Command arguments
316
+ """
317
+ if not args:
318
+ args = ["show"] # Default to show
319
+
320
+ subcommand = args[0].lower()
321
+
322
+ try:
323
+ if subcommand == "show":
324
+ detailed = "--detailed" in args or "-d" in args
325
+ await self.integration.show_status_snapshot(detailed)
326
+
327
+ elif subcommand == "start":
328
+ success = await self.integration.start_live_status_display()
329
+ if success:
330
+ self.console.print(
331
+ "[green]Live status display started. Press Ctrl+C to stop.[/green]"
332
+ )
333
+ try:
334
+ # Keep running until interrupted
335
+ while self.integration.is_live_display_running():
336
+ await asyncio.sleep(1)
337
+ except KeyboardInterrupt:
338
+ await self.integration.stop_live_status_display()
339
+ self.console.print(
340
+ "\n[yellow]Live status display stopped.[/yellow]"
341
+ )
342
+
343
+ elif subcommand == "stop":
344
+ await self.integration.stop_live_status_display()
345
+
346
+ elif subcommand == "quick":
347
+ status = await self.integration.get_quick_status()
348
+ self.console.print(status)
349
+
350
+ elif subcommand in ["help", "--help", "-h"]:
351
+ self._show_help()
352
+
353
+ else:
354
+ self.console.print(
355
+ f"[red]Unknown status subcommand: {subcommand}[/red]"
356
+ )
357
+ self._show_help()
358
+
359
+ except Exception as e:
360
+ logger.error(f"Status command failed: {e}")
361
+ self.console.print(f"[red]❌ Status command failed: {e}[/red]")
362
+
363
+ def _show_help(self) -> None:
364
+ """Show help for status commands."""
365
+ help_text = """[bold]Status Commands:[/bold]
366
+
367
+ [cyan]/status show[/cyan] - Show current status snapshot
368
+ [cyan]/status show --detailed[/cyan] - Show detailed status information
369
+ [cyan]/status start[/cyan] - Start live status display
370
+ [cyan]/status stop[/cyan] - Stop live status display
371
+ [cyan]/status quick[/cyan] - Get quick one-line status
372
+ [cyan]/status help[/cyan] - Show this help message
373
+
374
+ [bold]Examples:[/bold]
375
+ [cyan]/status show -d[/cyan] - Show detailed status
376
+ [cyan]/status start[/cyan] - Start live monitoring
377
+ """
378
+
379
+ self.console.print(
380
+ Panel(help_text, title="📊 Status Command Help", border_style="blue")
381
+ )
382
+
383
+
384
+ # Factory function for creating CLI integration
385
+ async def create_cli_status_integration(
386
+ config_manager: ConfigManager, console: Optional[Console] = None
387
+ ) -> CLIStatusIntegration:
388
+ """
389
+ Create a CLI status integration with a status-enhanced engine.
390
+
391
+ Args:
392
+ config_manager: Configuration manager
393
+ console: Rich console for output
394
+
395
+ Returns:
396
+ Configured CLI status integration
397
+ """
398
+ try:
399
+ # Create status-integrated engine
400
+ engine = await create_status_integrated_engine(config_manager)
401
+
402
+ # Create CLI integration
403
+ integration = CLIStatusIntegration(engine, console)
404
+
405
+ logger.info("CLI status integration created successfully")
406
+ return integration
407
+
408
+ except Exception as e:
409
+ logger.error(f"Failed to create CLI status integration: {e}")
410
+ raise
411
+
412
+
413
+ # Utility function to add status integration to existing engines
414
+ def add_status_integration_to_engine(
415
+ engine, console: Optional[Console] = None
416
+ ) -> CLIStatusIntegration:
417
+ """
418
+ Add status integration to an existing engine (if it supports it).
419
+
420
+ Args:
421
+ engine: Existing engine instance
422
+ console: Rich console for output
423
+
424
+ Returns:
425
+ CLI status integration instance
426
+ """
427
+ if isinstance(engine, StatusIntegratedAgentEngine):
428
+ return CLIStatusIntegration(engine, console)
429
+ else:
430
+ logger.warning(
431
+ f"Engine {type(engine).__name__} does not support status integration"
432
+ )
433
+ # Return a dummy integration that does nothing
434
+ return DummyCLIStatusIntegration(console)
435
+
436
+
437
+ class DummyCLIStatusIntegration:
438
+ """Dummy implementation for engines that don't support status integration."""
439
+
440
+ def __init__(self, console: Optional[Console] = None):
441
+ self.console = console or Console()
442
+
443
+ async def start_live_status_display(self) -> bool:
444
+ self.console.print(
445
+ "[yellow]Status display not available for this engine[/yellow]"
446
+ )
447
+ return False
448
+
449
+ async def stop_live_status_display(self) -> bool:
450
+ return True
451
+
452
+ async def show_status_snapshot(self, detailed: bool = False) -> None:
453
+ self.console.print(
454
+ "[yellow]Status information not available for this engine[/yellow]"
455
+ )
456
+
457
+ async def execute_with_status_display(
458
+ self, operation_func: Callable, *args, **kwargs
459
+ ) -> Any:
460
+ # Just execute without status display
461
+ if asyncio.iscoroutinefunction(operation_func):
462
+ return await operation_func(*args, **kwargs)
463
+ else:
464
+ return operation_func(*args, **kwargs)
465
+
466
+ def is_live_display_running(self) -> bool:
467
+ return False
468
+
469
+ async def get_quick_status(self) -> str:
470
+ return "Status not available"