kollabor 0.4.9__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.
- core/__init__.py +18 -0
- core/application.py +578 -0
- core/cli.py +193 -0
- core/commands/__init__.py +43 -0
- core/commands/executor.py +277 -0
- core/commands/menu_renderer.py +319 -0
- core/commands/parser.py +186 -0
- core/commands/registry.py +331 -0
- core/commands/system_commands.py +479 -0
- core/config/__init__.py +7 -0
- core/config/llm_task_config.py +110 -0
- core/config/loader.py +501 -0
- core/config/manager.py +112 -0
- core/config/plugin_config_manager.py +346 -0
- core/config/plugin_schema.py +424 -0
- core/config/service.py +399 -0
- core/effects/__init__.py +1 -0
- core/events/__init__.py +12 -0
- core/events/bus.py +129 -0
- core/events/executor.py +154 -0
- core/events/models.py +258 -0
- core/events/processor.py +176 -0
- core/events/registry.py +289 -0
- core/fullscreen/__init__.py +19 -0
- core/fullscreen/command_integration.py +290 -0
- core/fullscreen/components/__init__.py +12 -0
- core/fullscreen/components/animation.py +258 -0
- core/fullscreen/components/drawing.py +160 -0
- core/fullscreen/components/matrix_components.py +177 -0
- core/fullscreen/manager.py +302 -0
- core/fullscreen/plugin.py +204 -0
- core/fullscreen/renderer.py +282 -0
- core/fullscreen/session.py +324 -0
- core/io/__init__.py +52 -0
- core/io/buffer_manager.py +362 -0
- core/io/config_status_view.py +272 -0
- core/io/core_status_views.py +410 -0
- core/io/input_errors.py +313 -0
- core/io/input_handler.py +2655 -0
- core/io/input_mode_manager.py +402 -0
- core/io/key_parser.py +344 -0
- core/io/layout.py +587 -0
- core/io/message_coordinator.py +204 -0
- core/io/message_renderer.py +601 -0
- core/io/modal_interaction_handler.py +315 -0
- core/io/raw_input_processor.py +946 -0
- core/io/status_renderer.py +845 -0
- core/io/terminal_renderer.py +586 -0
- core/io/terminal_state.py +551 -0
- core/io/visual_effects.py +734 -0
- core/llm/__init__.py +26 -0
- core/llm/api_communication_service.py +863 -0
- core/llm/conversation_logger.py +473 -0
- core/llm/conversation_manager.py +414 -0
- core/llm/file_operations_executor.py +1401 -0
- core/llm/hook_system.py +402 -0
- core/llm/llm_service.py +1629 -0
- core/llm/mcp_integration.py +386 -0
- core/llm/message_display_service.py +450 -0
- core/llm/model_router.py +214 -0
- core/llm/plugin_sdk.py +396 -0
- core/llm/response_parser.py +848 -0
- core/llm/response_processor.py +364 -0
- core/llm/tool_executor.py +520 -0
- core/logging/__init__.py +19 -0
- core/logging/setup.py +208 -0
- core/models/__init__.py +5 -0
- core/models/base.py +23 -0
- core/plugins/__init__.py +13 -0
- core/plugins/collector.py +212 -0
- core/plugins/discovery.py +386 -0
- core/plugins/factory.py +263 -0
- core/plugins/registry.py +152 -0
- core/storage/__init__.py +5 -0
- core/storage/state_manager.py +84 -0
- core/ui/__init__.py +6 -0
- core/ui/config_merger.py +176 -0
- core/ui/config_widgets.py +369 -0
- core/ui/live_modal_renderer.py +276 -0
- core/ui/modal_actions.py +162 -0
- core/ui/modal_overlay_renderer.py +373 -0
- core/ui/modal_renderer.py +591 -0
- core/ui/modal_state_manager.py +443 -0
- core/ui/widget_integration.py +222 -0
- core/ui/widgets/__init__.py +27 -0
- core/ui/widgets/base_widget.py +136 -0
- core/ui/widgets/checkbox.py +85 -0
- core/ui/widgets/dropdown.py +140 -0
- core/ui/widgets/label.py +78 -0
- core/ui/widgets/slider.py +185 -0
- core/ui/widgets/text_input.py +224 -0
- core/utils/__init__.py +11 -0
- core/utils/config_utils.py +656 -0
- core/utils/dict_utils.py +212 -0
- core/utils/error_utils.py +275 -0
- core/utils/key_reader.py +171 -0
- core/utils/plugin_utils.py +267 -0
- core/utils/prompt_renderer.py +151 -0
- kollabor-0.4.9.dist-info/METADATA +298 -0
- kollabor-0.4.9.dist-info/RECORD +128 -0
- kollabor-0.4.9.dist-info/WHEEL +5 -0
- kollabor-0.4.9.dist-info/entry_points.txt +2 -0
- kollabor-0.4.9.dist-info/licenses/LICENSE +21 -0
- kollabor-0.4.9.dist-info/top_level.txt +4 -0
- kollabor_cli_main.py +20 -0
- plugins/__init__.py +1 -0
- plugins/enhanced_input/__init__.py +18 -0
- plugins/enhanced_input/box_renderer.py +103 -0
- plugins/enhanced_input/box_styles.py +142 -0
- plugins/enhanced_input/color_engine.py +165 -0
- plugins/enhanced_input/config.py +150 -0
- plugins/enhanced_input/cursor_manager.py +72 -0
- plugins/enhanced_input/geometry.py +81 -0
- plugins/enhanced_input/state.py +130 -0
- plugins/enhanced_input/text_processor.py +115 -0
- plugins/enhanced_input_plugin.py +385 -0
- plugins/fullscreen/__init__.py +9 -0
- plugins/fullscreen/example_plugin.py +327 -0
- plugins/fullscreen/matrix_plugin.py +132 -0
- plugins/hook_monitoring_plugin.py +1299 -0
- plugins/query_enhancer_plugin.py +350 -0
- plugins/save_conversation_plugin.py +502 -0
- plugins/system_commands_plugin.py +93 -0
- plugins/tmux_plugin.py +795 -0
- plugins/workflow_enforcement_plugin.py +629 -0
- system_prompt/default.md +1286 -0
- system_prompt/default_win.md +265 -0
- system_prompt/example_with_trender.md +47 -0
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
"""Hook Monitoring Plugin for development and debugging.
|
|
2
|
+
|
|
3
|
+
[SHOWCASE] SHOWCASE PLUGIN: Demonstrates ALL plugin ecosystem features! [SHOWCASE]
|
|
4
|
+
|
|
5
|
+
This plugin serves as a comprehensive example of the Kollabor CLI plugin ecosystem,
|
|
6
|
+
demonstrating:
|
|
7
|
+
- Hook monitoring and performance tracking
|
|
8
|
+
- Plugin discovery via PluginFactory
|
|
9
|
+
- Cross-plugin service registration via KollaborPluginSDK
|
|
10
|
+
- Direct plugin-to-plugin communication
|
|
11
|
+
- Event bus messaging
|
|
12
|
+
- Dynamic service discovery patterns
|
|
13
|
+
- Plugin health dashboard functionality
|
|
14
|
+
|
|
15
|
+
Perfect for developers learning the plugin system!
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import datetime
|
|
19
|
+
import logging
|
|
20
|
+
import time
|
|
21
|
+
from typing import Any, Dict, List, Optional
|
|
22
|
+
|
|
23
|
+
# Import event system components
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
27
|
+
|
|
28
|
+
from core.events import Event, EventType, Hook, HookPriority
|
|
29
|
+
|
|
30
|
+
# [TOOL] PLUGIN ECOSYSTEM IMPORTS - Showcasing factory and SDK integration
|
|
31
|
+
try:
|
|
32
|
+
from core.llm.plugin_sdk import KollaborPluginSDK
|
|
33
|
+
from core.plugins.factory import PluginFactory
|
|
34
|
+
SDK_AVAILABLE = True
|
|
35
|
+
except ImportError:
|
|
36
|
+
# Graceful degradation if SDK not available
|
|
37
|
+
SDK_AVAILABLE = False
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class HookMonitoringPlugin:
|
|
43
|
+
"""[SHOWCASE] SHOWCASE: A comprehensive hook monitoring system demonstrating ALL plugin ecosystem features!"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, name: str, state_manager, event_bus, renderer, config) -> None:
|
|
46
|
+
"""Initialize the hook monitoring plugin with full ecosystem integration.
|
|
47
|
+
|
|
48
|
+
This initialization showcases:
|
|
49
|
+
- Basic plugin setup
|
|
50
|
+
- Plugin factory access for service discovery
|
|
51
|
+
- SDK initialization for service registration
|
|
52
|
+
- Cross-plugin communication setup
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
name: Plugin name.
|
|
56
|
+
state_manager: State management system.
|
|
57
|
+
event_bus: Event bus for hook registration.
|
|
58
|
+
renderer: Terminal renderer.
|
|
59
|
+
config: Configuration manager.
|
|
60
|
+
"""
|
|
61
|
+
# [DATA] BASIC PLUGIN SETUP
|
|
62
|
+
self.name = name
|
|
63
|
+
self.state_manager = state_manager
|
|
64
|
+
self.event_bus = event_bus
|
|
65
|
+
self.renderer = renderer
|
|
66
|
+
self.config = config
|
|
67
|
+
logger.info(f"[INIT] Initializing HookMonitoringPlugin: {name}")
|
|
68
|
+
|
|
69
|
+
# [DATA] HOOK MONITORING STATE - Core monitoring functionality
|
|
70
|
+
self.hook_executions = 0
|
|
71
|
+
self.last_hook_event = "None"
|
|
72
|
+
self.failed_hooks = 0
|
|
73
|
+
self.timeout_hooks = 0
|
|
74
|
+
self.hook_performance = {} # event_type -> {total_time, count, avg_time}
|
|
75
|
+
self.error_log = [] # Recent errors for debugging
|
|
76
|
+
self.hook_health_status = "Starting"
|
|
77
|
+
|
|
78
|
+
# [FIND] PLUGIN ECOSYSTEM STATE - Showcasing service discovery
|
|
79
|
+
self.discovered_plugins = {} # plugin_name -> plugin_instance
|
|
80
|
+
self.available_services = {} # service_name -> plugin_info
|
|
81
|
+
self.plugin_health_stats = {} # plugin_name -> health_metrics
|
|
82
|
+
self.cross_plugin_messages = [] # Recent inter-plugin communications
|
|
83
|
+
|
|
84
|
+
# [TOOL] PLUGIN FACTORY ACCESS - Demonstrating plugin discovery
|
|
85
|
+
# This shows how plugins can discover and communicate with each other
|
|
86
|
+
self.plugin_factory: Optional[PluginFactory] = None
|
|
87
|
+
self.plugin_discovery_enabled = config.get("plugins.hook_monitoring.enable_plugin_discovery", True)
|
|
88
|
+
|
|
89
|
+
# [TOOL] SDK INITIALIZATION - Demonstrating service registration
|
|
90
|
+
# This shows how plugins can register services for other plugins to use
|
|
91
|
+
self.sdk: Optional[KollaborPluginSDK] = None
|
|
92
|
+
self.service_registration_enabled = config.get("plugins.hook_monitoring.enable_service_registration", True)
|
|
93
|
+
|
|
94
|
+
if SDK_AVAILABLE and self.service_registration_enabled:
|
|
95
|
+
self.sdk = KollaborPluginSDK()
|
|
96
|
+
logger.info("SDK initialized - ready for service registration")
|
|
97
|
+
|
|
98
|
+
# [COMM] CROSS-PLUGIN COMMUNICATION - Setup for plugin messaging
|
|
99
|
+
self.enable_cross_plugin_comm = config.get("plugins.hook_monitoring.enable_cross_plugin_communication", True)
|
|
100
|
+
self.message_history_limit = config.get("plugins.hook_monitoring.message_history_limit", 20)
|
|
101
|
+
|
|
102
|
+
# [TARGET] CREATE HOOKS - Standard hook creation for monitoring
|
|
103
|
+
self.hooks = self._create_all_hooks()
|
|
104
|
+
|
|
105
|
+
logger.debug(f"HookMonitoringPlugin fully initialized with ecosystem features!")
|
|
106
|
+
|
|
107
|
+
def get_status_lines(self) -> Dict[str, List[str]]:
|
|
108
|
+
"""Get status lines for the hook monitoring plugin organized by area.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Dictionary with status lines organized by areas A, B, C.
|
|
112
|
+
"""
|
|
113
|
+
# Check if status display is enabled for this plugin
|
|
114
|
+
show_status = self.config.get('plugins.hook_monitoring.show_status', True)
|
|
115
|
+
if not show_status:
|
|
116
|
+
return {"A": [], "B": [], "C": []}
|
|
117
|
+
|
|
118
|
+
enabled = self.config.get('plugins.hook_monitoring.enabled', False)
|
|
119
|
+
debug_mode = self.config.get('plugins.hook_monitoring.debug_logging', False)
|
|
120
|
+
|
|
121
|
+
# Hook monitoring status goes to area B (system monitoring)
|
|
122
|
+
if not enabled:
|
|
123
|
+
return {"A": [], "B": ["Hook Monitor: Off"], "C": []}
|
|
124
|
+
|
|
125
|
+
# Calculate failure rate for health display
|
|
126
|
+
failure_rate = 0
|
|
127
|
+
if self.hook_executions > 0:
|
|
128
|
+
failure_rate = (self.failed_hooks + self.timeout_hooks) / self.hook_executions
|
|
129
|
+
|
|
130
|
+
# [FIND] SHOWCASE: Plugin Discovery Status
|
|
131
|
+
discovered_count = len(getattr(self, 'discovered_plugins', {}))
|
|
132
|
+
|
|
133
|
+
# [TOOL] SHOWCASE: Service Registration Status
|
|
134
|
+
registered_services = 3 if (self.service_registration_enabled and SDK_AVAILABLE) else 0
|
|
135
|
+
|
|
136
|
+
# [COMM] SHOWCASE: Cross-Plugin Communication Status
|
|
137
|
+
recent_messages = len(getattr(self, 'cross_plugin_messages', []))
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
"A": [], # No area A content for hook monitoring
|
|
141
|
+
"B": [ # System monitoring goes in area B
|
|
142
|
+
f"Monitor: {self.hook_health_status}",
|
|
143
|
+
f"Executions: {self.hook_executions}",
|
|
144
|
+
f"Plugins: {discovered_count}",
|
|
145
|
+
f"Services: {registered_services}",
|
|
146
|
+
f"Messages: {recent_messages}",
|
|
147
|
+
f"Rate: {failure_rate:.1%}" if self.hook_executions > 0 else "[FAST] Rate: N/A"
|
|
148
|
+
],
|
|
149
|
+
"C": [ # Detailed ecosystem info in area C
|
|
150
|
+
f"SHOWCASE: Plugin Ecosystem Demo",
|
|
151
|
+
f"Last Event: {self.last_hook_event[:20]}",
|
|
152
|
+
f"Discovery: {'[OK]' if self.plugin_discovery_enabled else '[X]'}",
|
|
153
|
+
f"SDK: {'[OK]' if SDK_AVAILABLE else '[X]'}",
|
|
154
|
+
f"Debug: {'On' if debug_mode else 'Off'}"
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async def initialize(self) -> None:
|
|
159
|
+
"""[INIT] SHOWCASE: Initialize with full plugin ecosystem integration!
|
|
160
|
+
|
|
161
|
+
This method demonstrates:
|
|
162
|
+
1. Plugin factory access for discovering other plugins
|
|
163
|
+
2. SDK service registration for providing monitoring services
|
|
164
|
+
3. Cross-plugin communication setup
|
|
165
|
+
4. Dynamic service discovery patterns
|
|
166
|
+
"""
|
|
167
|
+
logger.info("Starting HookMonitoringPlugin initialization...")
|
|
168
|
+
|
|
169
|
+
# [FIND] STEP 1: PLUGIN DISCOVERY - Demonstrating how to find other plugins
|
|
170
|
+
if self.plugin_discovery_enabled:
|
|
171
|
+
await self._discover_other_plugins()
|
|
172
|
+
|
|
173
|
+
# [TOOL] STEP 2: SERVICE REGISTRATION - Showcasing how to offer services to other plugins
|
|
174
|
+
if self.service_registration_enabled and self.sdk:
|
|
175
|
+
await self._register_monitoring_services()
|
|
176
|
+
|
|
177
|
+
# [COMM] STEP 3: CROSS-PLUGIN COMMUNICATION SETUP
|
|
178
|
+
if self.enable_cross_plugin_comm:
|
|
179
|
+
await self._setup_cross_plugin_communication()
|
|
180
|
+
|
|
181
|
+
# [DATA] STEP 4: INITIALIZE PLUGIN HEALTH MONITORING
|
|
182
|
+
await self._initialize_plugin_health_monitoring()
|
|
183
|
+
|
|
184
|
+
logger.info("HookMonitoringPlugin initialization complete - all ecosystem features active!")
|
|
185
|
+
|
|
186
|
+
async def _discover_other_plugins(self) -> None:
|
|
187
|
+
"""[FIND] SHOWCASE: Discover other plugins using PluginFactory.
|
|
188
|
+
|
|
189
|
+
This demonstrates the core pattern for plugin discovery:
|
|
190
|
+
- Access the plugin factory (would typically be injected)
|
|
191
|
+
- Get all plugin instances
|
|
192
|
+
- Analyze their capabilities
|
|
193
|
+
- Store references for later communication
|
|
194
|
+
"""
|
|
195
|
+
logger.debug("Discovering other plugins in the ecosystem...")
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
# [TOOL] ACCESS PLUGIN FACTORY - In real implementation, this would be injected
|
|
199
|
+
# For demonstration, we simulate what the factory discovery looks like
|
|
200
|
+
if hasattr(self.renderer, 'plugin_instances'):
|
|
201
|
+
# This simulates getting access to the factory through the renderer
|
|
202
|
+
plugin_instances = getattr(self.renderer, 'plugin_instances', {})
|
|
203
|
+
else:
|
|
204
|
+
# Fallback demonstration data
|
|
205
|
+
plugin_instances = {
|
|
206
|
+
"EnhancedInputPlugin": "simulated_input_plugin",
|
|
207
|
+
"WorkflowEnforcementPlugin": "simulated_workflow_plugin",
|
|
208
|
+
# This would be populated by: factory.get_all_instances()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
self.discovered_plugins = plugin_instances
|
|
212
|
+
|
|
213
|
+
# [DATA] ANALYZE DISCOVERED PLUGINS - Check their capabilities
|
|
214
|
+
for plugin_name, plugin_instance in plugin_instances.items():
|
|
215
|
+
if plugin_name != self.name: # Don't analyze ourselves
|
|
216
|
+
await self._analyze_plugin_capabilities(plugin_name, plugin_instance)
|
|
217
|
+
|
|
218
|
+
logger.info(f"Discovered {len(self.discovered_plugins)} plugins: {list(self.discovered_plugins.keys())}")
|
|
219
|
+
|
|
220
|
+
except Exception as e:
|
|
221
|
+
logger.warning(f"Plugin discovery failed (demonstration mode): {e}")
|
|
222
|
+
# In production, this would use: factory.get_all_instances()
|
|
223
|
+
|
|
224
|
+
async def _analyze_plugin_capabilities(self, plugin_name: str, plugin_instance: Any) -> None:
|
|
225
|
+
"""[FIND] SHOWCASE: Analyze what services a plugin provides.
|
|
226
|
+
|
|
227
|
+
This demonstrates how to discover plugin capabilities:
|
|
228
|
+
- Check for service methods
|
|
229
|
+
- Analyze configuration options
|
|
230
|
+
- Determine communication interfaces
|
|
231
|
+
"""
|
|
232
|
+
capabilities = {
|
|
233
|
+
"has_get_services": hasattr(plugin_instance, 'get_services'),
|
|
234
|
+
"has_status_lines": hasattr(plugin_instance, 'get_status_lines'),
|
|
235
|
+
"has_initialize": hasattr(plugin_instance, 'initialize'),
|
|
236
|
+
"has_register_hooks": hasattr(plugin_instance, 'register_hooks'),
|
|
237
|
+
"supports_messaging": hasattr(plugin_instance, 'handle_message'),
|
|
238
|
+
"plugin_type": type(plugin_instance).__name__ if plugin_instance != "simulated_input_plugin" else "EnhancedInputPlugin"
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# [NOTE] STORE PLUGIN INFORMATION - For later use in health monitoring
|
|
242
|
+
self.plugin_health_stats[plugin_name] = {
|
|
243
|
+
"capabilities": capabilities,
|
|
244
|
+
"last_seen": datetime.datetime.now(),
|
|
245
|
+
"status": "discovered",
|
|
246
|
+
"message_count": 0
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
logger.debug(f"Analyzed {plugin_name}: {capabilities}")
|
|
250
|
+
|
|
251
|
+
async def _register_monitoring_services(self) -> None:
|
|
252
|
+
"""[TOOL] SHOWCASE: Register monitoring services for other plugins to use.
|
|
253
|
+
|
|
254
|
+
This demonstrates how plugins offer services to the ecosystem:
|
|
255
|
+
- Register performance monitoring service
|
|
256
|
+
- Register health check service
|
|
257
|
+
- Register metrics collection service
|
|
258
|
+
"""
|
|
259
|
+
logger.debug("Registering monitoring services for other plugins...")
|
|
260
|
+
|
|
261
|
+
if not self.sdk:
|
|
262
|
+
logger.warning("SDK not available - cannot register services")
|
|
263
|
+
return
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
# [DATA] SERVICE 1: Performance Monitoring
|
|
267
|
+
self.sdk.register_custom_tool({
|
|
268
|
+
"name": "monitor_performance",
|
|
269
|
+
"description": "Monitor plugin performance and hook execution times",
|
|
270
|
+
"handler": self._provide_performance_monitoring,
|
|
271
|
+
"parameters": {
|
|
272
|
+
"plugin_name": {"type": "string", "description": "Plugin to monitor"},
|
|
273
|
+
"metric_type": {"type": "string", "description": "Type of metric to collect"}
|
|
274
|
+
},
|
|
275
|
+
"plugin": self.name,
|
|
276
|
+
"enabled": True,
|
|
277
|
+
"category": "monitoring"
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
# [HEALTH] SERVICE 2: Health Checking
|
|
281
|
+
self.sdk.register_custom_tool({
|
|
282
|
+
"name": "check_plugin_health",
|
|
283
|
+
"description": "Check the health status of any plugin in the system",
|
|
284
|
+
"handler": self._provide_health_check,
|
|
285
|
+
"parameters": {
|
|
286
|
+
"plugin_name": {"type": "string", "description": "Plugin to check"},
|
|
287
|
+
"detailed": {"type": "boolean", "description": "Return detailed health info"}
|
|
288
|
+
},
|
|
289
|
+
"plugin": self.name,
|
|
290
|
+
"enabled": True,
|
|
291
|
+
"category": "health"
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
# [METRICS] SERVICE 3: Metrics Collection
|
|
295
|
+
self.sdk.register_custom_tool({
|
|
296
|
+
"name": "collect_system_metrics",
|
|
297
|
+
"description": "Collect comprehensive system and plugin metrics",
|
|
298
|
+
"handler": self._provide_metrics_collection,
|
|
299
|
+
"parameters": {
|
|
300
|
+
"time_range": {"type": "string", "description": "Time range for metrics"},
|
|
301
|
+
"include_performance": {"type": "boolean", "description": "Include performance data"}
|
|
302
|
+
},
|
|
303
|
+
"plugin": self.name,
|
|
304
|
+
"enabled": True,
|
|
305
|
+
"category": "analytics"
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
logger.debug("Registered 3 monitoring services - other plugins can now use our services!")
|
|
309
|
+
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.error(f"Service registration failed: {e}")
|
|
312
|
+
|
|
313
|
+
async def _setup_cross_plugin_communication(self) -> None:
|
|
314
|
+
"""[COMM] SHOWCASE: Setup cross-plugin communication channels.
|
|
315
|
+
|
|
316
|
+
This demonstrates how to:
|
|
317
|
+
- Set up message handlers for plugin-to-plugin communication
|
|
318
|
+
- Register for event bus notifications
|
|
319
|
+
- Create communication protocols
|
|
320
|
+
"""
|
|
321
|
+
logger.debug("Setting up cross-plugin communication...")
|
|
322
|
+
|
|
323
|
+
# [COMM] REGISTER MESSAGE HANDLER - For receiving messages from other plugins
|
|
324
|
+
# In a real implementation, this would integrate with the event bus
|
|
325
|
+
self.message_handlers = {
|
|
326
|
+
"health_check_request": self._handle_health_check_request,
|
|
327
|
+
"performance_data_request": self._handle_performance_data_request,
|
|
328
|
+
"plugin_status_update": self._handle_plugin_status_update
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
logger.debug("Cross-plugin communication setup complete!")
|
|
332
|
+
|
|
333
|
+
async def _initialize_plugin_health_monitoring(self) -> None:
|
|
334
|
+
"""[DATA] SHOWCASE: Initialize comprehensive plugin health monitoring.
|
|
335
|
+
|
|
336
|
+
This sets up monitoring for:
|
|
337
|
+
- Plugin performance metrics
|
|
338
|
+
- Communication patterns
|
|
339
|
+
- Service usage statistics
|
|
340
|
+
- System health indicators
|
|
341
|
+
"""
|
|
342
|
+
logger.debug("Initializing plugin health monitoring...")
|
|
343
|
+
|
|
344
|
+
# [TARGET] HEALTH MONITORING CONFIGURATION
|
|
345
|
+
self.health_monitoring = {
|
|
346
|
+
"enabled": True,
|
|
347
|
+
"check_interval": self.config.get("plugins.hook_monitoring.health_check_interval", 30),
|
|
348
|
+
"performance_threshold": self.config.get("plugins.hook_monitoring.performance_threshold_ms", 100),
|
|
349
|
+
"memory_threshold": self.config.get("plugins.hook_monitoring.memory_threshold_mb", 50)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# [METRICS] METRICS COLLECTION SETUP
|
|
353
|
+
self.metrics_collection = {
|
|
354
|
+
"hook_performance": {},
|
|
355
|
+
"plugin_communications": [],
|
|
356
|
+
"service_usage": {},
|
|
357
|
+
"error_patterns": []
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
logger.debug("Plugin health monitoring initialized - comprehensive monitoring active!")
|
|
361
|
+
|
|
362
|
+
async def register_hooks(self) -> None:
|
|
363
|
+
"""Register hook monitoring plugin hooks for all event types."""
|
|
364
|
+
if not self.config.get('plugins.hook_monitoring.enabled', True):
|
|
365
|
+
logger.info("Hook monitoring plugin disabled, not registering hooks")
|
|
366
|
+
return
|
|
367
|
+
|
|
368
|
+
logger.info(f"Hook Monitor: Registering {len(self.hooks)} monitoring hooks for system health tracking")
|
|
369
|
+
|
|
370
|
+
for hook in self.hooks:
|
|
371
|
+
try:
|
|
372
|
+
await self.event_bus.register_hook(hook)
|
|
373
|
+
logger.debug(f"Hook Monitor: Registered {hook.name} for {hook.event_type.value}")
|
|
374
|
+
except Exception as e:
|
|
375
|
+
logger.error(f"Hook Monitor: Failed to register {hook.name}: {e}")
|
|
376
|
+
|
|
377
|
+
logger.info("Hook Monitor: Registration completed - monitoring system active")
|
|
378
|
+
|
|
379
|
+
# [DATA] REGISTER STATUS VIEW - Register custom status view for developer metrics
|
|
380
|
+
await self._register_status_view()
|
|
381
|
+
|
|
382
|
+
async def _register_status_view(self) -> None:
|
|
383
|
+
"""Register developer metrics status view."""
|
|
384
|
+
try:
|
|
385
|
+
# Check if renderer has status registry
|
|
386
|
+
if (hasattr(self.renderer, 'status_renderer') and
|
|
387
|
+
self.renderer.status_renderer and
|
|
388
|
+
hasattr(self.renderer.status_renderer, 'status_registry') and
|
|
389
|
+
self.renderer.status_renderer.status_registry):
|
|
390
|
+
|
|
391
|
+
from core.io.status_renderer import StatusViewConfig, BlockConfig
|
|
392
|
+
|
|
393
|
+
# Create developer metrics view
|
|
394
|
+
developer_view = StatusViewConfig(
|
|
395
|
+
name="Developer Metrics",
|
|
396
|
+
plugin_source="hook_monitoring",
|
|
397
|
+
priority=400, # Lower than core views
|
|
398
|
+
blocks=[
|
|
399
|
+
BlockConfig(
|
|
400
|
+
width_fraction=1.0,
|
|
401
|
+
content_provider=self._get_developer_metrics_content,
|
|
402
|
+
title="Developer Metrics",
|
|
403
|
+
priority=100
|
|
404
|
+
)
|
|
405
|
+
]
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
registry = self.renderer.status_renderer.status_registry
|
|
409
|
+
registry.register_status_view("hook_monitoring", developer_view)
|
|
410
|
+
logger.info("[OK] Registered 'Developer Metrics' status view")
|
|
411
|
+
|
|
412
|
+
else:
|
|
413
|
+
logger.warning("Status registry not available - cannot register status view")
|
|
414
|
+
|
|
415
|
+
except Exception as e:
|
|
416
|
+
logger.error(f"Failed to register status view: {e}")
|
|
417
|
+
|
|
418
|
+
def _get_developer_metrics_content(self) -> List[str]:
|
|
419
|
+
"""Get developer metrics content for status view."""
|
|
420
|
+
try:
|
|
421
|
+
enabled = self.config.get('plugins.hook_monitoring.enabled', False)
|
|
422
|
+
if not enabled:
|
|
423
|
+
return ["Hook Monitor: - Off"]
|
|
424
|
+
|
|
425
|
+
# Calculate failure rate for health display
|
|
426
|
+
failure_rate = 0
|
|
427
|
+
if self.hook_executions > 0:
|
|
428
|
+
failure_rate = (self.failed_hooks + self.timeout_hooks) / self.hook_executions
|
|
429
|
+
|
|
430
|
+
# Plugin discovery status
|
|
431
|
+
discovered_count = len(getattr(self, 'discovered_plugins', {}))
|
|
432
|
+
|
|
433
|
+
# Service registration status
|
|
434
|
+
registered_services = 3 if (self.service_registration_enabled and SDK_AVAILABLE) else 0
|
|
435
|
+
|
|
436
|
+
# Cross-plugin communication status
|
|
437
|
+
recent_messages = len(getattr(self, 'cross_plugin_messages', []))
|
|
438
|
+
|
|
439
|
+
return [
|
|
440
|
+
f"√ Monitor: {self.hook_health_status} ··· Executions: {self.hook_executions}",
|
|
441
|
+
f"+ Plugins: {discovered_count} ··· × Services: {registered_services} ··· Rate: {failure_rate:.1%}" if self.hook_executions > 0 else f"+ Plugins: {discovered_count} ··· × Services: {registered_services} ··· Rate: N/A"
|
|
442
|
+
]
|
|
443
|
+
|
|
444
|
+
except Exception as e:
|
|
445
|
+
logger.error(f"Error getting developer metrics content: {e}")
|
|
446
|
+
return ["Developer Metrics: Error"]
|
|
447
|
+
|
|
448
|
+
async def shutdown(self) -> None:
|
|
449
|
+
"""Shutdown the hook monitoring plugin."""
|
|
450
|
+
logger.info(f"Hook Monitor: Shutting down - processed {self.hook_executions} events, {self.failed_hooks} failures")
|
|
451
|
+
self._log_final_report()
|
|
452
|
+
# Only show shutdown message if not in pipe mode
|
|
453
|
+
# if not getattr(self.renderer, 'pipe_mode', False):
|
|
454
|
+
# print("\rHook Monitor shut down")
|
|
455
|
+
|
|
456
|
+
@staticmethod
|
|
457
|
+
def get_default_config() -> Dict[str, Any]:
|
|
458
|
+
"""[TOOL] SHOWCASE: Comprehensive configuration for hook monitoring plugin.
|
|
459
|
+
|
|
460
|
+
This configuration demonstrates all available plugin ecosystem features:
|
|
461
|
+
- Basic monitoring settings
|
|
462
|
+
- Plugin discovery configuration
|
|
463
|
+
- Service registration settings
|
|
464
|
+
- Cross-plugin communication options
|
|
465
|
+
- Health monitoring parameters
|
|
466
|
+
"""
|
|
467
|
+
return {
|
|
468
|
+
"plugins": {
|
|
469
|
+
"hook_monitoring": {
|
|
470
|
+
# [DATA] BASIC MONITORING CONFIGURATION
|
|
471
|
+
"enabled": True,
|
|
472
|
+
"debug_logging": True,
|
|
473
|
+
"show_status": True,
|
|
474
|
+
"hook_timeout": 5,
|
|
475
|
+
"log_all_events": True,
|
|
476
|
+
"log_event_data": False,
|
|
477
|
+
"log_performance": True,
|
|
478
|
+
"log_failures_only": False,
|
|
479
|
+
"performance_threshold_ms": 100,
|
|
480
|
+
"max_error_log_size": 50,
|
|
481
|
+
|
|
482
|
+
# [FIND] PLUGIN DISCOVERY CONFIGURATION - Showcase feature
|
|
483
|
+
"enable_plugin_discovery": True,
|
|
484
|
+
"discovery_interval": 30, # seconds
|
|
485
|
+
"auto_analyze_capabilities": True,
|
|
486
|
+
|
|
487
|
+
# [TOOL] SERVICE REGISTRATION CONFIGURATION - Showcase feature
|
|
488
|
+
"enable_service_registration": True,
|
|
489
|
+
"register_performance_service": True,
|
|
490
|
+
"register_health_service": True,
|
|
491
|
+
"register_metrics_service": True,
|
|
492
|
+
|
|
493
|
+
# [COMM] CROSS-PLUGIN COMMUNICATION - Showcase feature
|
|
494
|
+
"enable_cross_plugin_communication": True,
|
|
495
|
+
"message_history_limit": 20,
|
|
496
|
+
"auto_respond_to_health_checks": True,
|
|
497
|
+
|
|
498
|
+
# [HEALTH] HEALTH MONITORING CONFIGURATION - Showcase feature
|
|
499
|
+
"health_check_interval": 30, # seconds
|
|
500
|
+
"memory_threshold_mb": 50,
|
|
501
|
+
"performance_degradation_threshold": 0.15,
|
|
502
|
+
|
|
503
|
+
# [METRICS] METRICS COLLECTION - Showcase feature
|
|
504
|
+
"collect_plugin_metrics": True,
|
|
505
|
+
"metrics_retention_hours": 24,
|
|
506
|
+
"detailed_performance_tracking": True,
|
|
507
|
+
|
|
508
|
+
# [TARGET] DASHBOARD FEATURES - Showcase feature
|
|
509
|
+
"enable_health_dashboard": True,
|
|
510
|
+
"dashboard_update_interval": 10, # seconds
|
|
511
|
+
"show_plugin_interactions": True,
|
|
512
|
+
"show_service_usage": True
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
@staticmethod
|
|
518
|
+
def get_startup_info(config) -> List[str]:
|
|
519
|
+
"""[INIT] SHOWCASE: Startup information displaying all ecosystem features.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
config: Configuration manager instance.
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
List of strings to display during startup.
|
|
526
|
+
"""
|
|
527
|
+
return [
|
|
528
|
+
f"[SHOWCASE] HOOK MONITORING SHOWCASE PLUGIN",
|
|
529
|
+
f"Monitor: {config.get('plugins.hook_monitoring.enabled')}",
|
|
530
|
+
f"Plugin Discovery: {config.get('plugins.hook_monitoring.enable_plugin_discovery')}",
|
|
531
|
+
f"Service Registration: {config.get('plugins.hook_monitoring.enable_service_registration')}",
|
|
532
|
+
f"Cross-Plugin Comm: {config.get('plugins.hook_monitoring.enable_cross_plugin_communication')}",
|
|
533
|
+
f"Health Dashboard: {config.get('plugins.hook_monitoring.enable_health_dashboard')}",
|
|
534
|
+
f"Performance Threshold: {config.get('plugins.hook_monitoring.performance_threshold_ms')}ms",
|
|
535
|
+
f"[TARGET] Demonstrates ALL plugin ecosystem features!"
|
|
536
|
+
]
|
|
537
|
+
|
|
538
|
+
@staticmethod
|
|
539
|
+
def get_config_widgets() -> Dict[str, Any]:
|
|
540
|
+
"""Get configuration widgets for this plugin.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
Widget section definition for the config modal.
|
|
544
|
+
"""
|
|
545
|
+
return {
|
|
546
|
+
"title": "Hook Monitoring Plugin",
|
|
547
|
+
"widgets": [
|
|
548
|
+
{"type": "checkbox", "label": "Debug Logging", "config_path": "plugins.hook_monitoring.debug_logging", "help": "Enable detailed debug logging for hooks"},
|
|
549
|
+
{"type": "checkbox", "label": "Show Status", "config_path": "plugins.hook_monitoring.show_status", "help": "Display hook monitoring status"},
|
|
550
|
+
{"type": "slider", "label": "Hook Timeout", "config_path": "plugins.hook_monitoring.hook_timeout", "min_value": 1, "max_value": 30, "step": 1, "help": "Timeout for hook execution in seconds"},
|
|
551
|
+
{"type": "checkbox", "label": "Log All Events", "config_path": "plugins.hook_monitoring.log_all_events", "help": "Log every hook event"},
|
|
552
|
+
{"type": "checkbox", "label": "Log Event Data", "config_path": "plugins.hook_monitoring.log_event_data", "help": "Include event data in logs"},
|
|
553
|
+
{"type": "checkbox", "label": "Log Performance", "config_path": "plugins.hook_monitoring.log_performance", "help": "Log performance metrics for hooks"},
|
|
554
|
+
{"type": "checkbox", "label": "Log Failures Only", "config_path": "plugins.hook_monitoring.log_failures_only", "help": "Only log failed hook executions"},
|
|
555
|
+
{"type": "slider", "label": "Performance Threshold", "config_path": "plugins.hook_monitoring.performance_threshold_ms", "min_value": 10, "max_value": 1000, "step": 10, "help": "Performance warning threshold in milliseconds"},
|
|
556
|
+
{"type": "slider", "label": "Max Error Log Size", "config_path": "plugins.hook_monitoring.max_error_log_size", "min_value": 10, "max_value": 500, "step": 10, "help": "Maximum error log entries to keep"},
|
|
557
|
+
{"type": "checkbox", "label": "Enable Plugin Discovery", "config_path": "plugins.hook_monitoring.enable_plugin_discovery", "help": "Automatically discover new plugins"},
|
|
558
|
+
{"type": "slider", "label": "Discovery Interval", "config_path": "plugins.hook_monitoring.discovery_interval", "min_value": 5, "max_value": 300, "step": 5, "help": "Plugin discovery interval in seconds"},
|
|
559
|
+
{"type": "checkbox", "label": "Auto Analyze Capabilities", "config_path": "plugins.hook_monitoring.auto_analyze_capabilities", "help": "Automatically analyze plugin capabilities"},
|
|
560
|
+
{"type": "checkbox", "label": "Enable Service Registration", "config_path": "plugins.hook_monitoring.enable_service_registration", "help": "Register monitoring services with event bus"},
|
|
561
|
+
{"type": "checkbox", "label": "Register Performance Service", "config_path": "plugins.hook_monitoring.register_performance_service", "help": "Register performance monitoring service"},
|
|
562
|
+
{"type": "checkbox", "label": "Register Health Service", "config_path": "plugins.hook_monitoring.register_health_service", "help": "Register health monitoring service"},
|
|
563
|
+
{"type": "checkbox", "label": "Register Metrics Service", "config_path": "plugins.hook_monitoring.register_metrics_service", "help": "Register metrics collection service"},
|
|
564
|
+
{"type": "checkbox", "label": "Enable Cross Plugin Communication", "config_path": "plugins.hook_monitoring.enable_cross_plugin_communication", "help": "Allow plugins to communicate with each other"},
|
|
565
|
+
{"type": "slider", "label": "Message History Limit", "config_path": "plugins.hook_monitoring.message_history_limit", "min_value": 5, "max_value": 100, "step": 5, "help": "Maximum message history entries"},
|
|
566
|
+
{"type": "checkbox", "label": "Auto Respond to Health Checks", "config_path": "plugins.hook_monitoring.auto_respond_to_health_checks", "help": "Automatically respond to health check requests"},
|
|
567
|
+
{"type": "slider", "label": "Health Check Interval", "config_path": "plugins.hook_monitoring.health_check_interval", "min_value": 10, "max_value": 300, "step": 10, "help": "Health check interval in seconds"},
|
|
568
|
+
{"type": "slider", "label": "Memory Threshold MB", "config_path": "plugins.hook_monitoring.memory_threshold_mb", "min_value": 10, "max_value": 500, "step": 10, "help": "Memory usage warning threshold in MB"},
|
|
569
|
+
{"type": "slider", "label": "Performance Degradation Threshold", "config_path": "plugins.hook_monitoring.performance_degradation_threshold", "min_value": 0.05, "max_value": 0.5, "step": 0.05, "help": "Performance degradation warning threshold"},
|
|
570
|
+
{"type": "checkbox", "label": "Collect Plugin Metrics", "config_path": "plugins.hook_monitoring.collect_plugin_metrics", "help": "Collect detailed metrics for all plugins"},
|
|
571
|
+
{"type": "slider", "label": "Metrics Retention Hours", "config_path": "plugins.hook_monitoring.metrics_retention_hours", "min_value": 1, "max_value": 168, "step": 1, "help": "How long to retain metrics data (hours)"},
|
|
572
|
+
{"type": "checkbox", "label": "Detailed Performance Tracking", "config_path": "plugins.hook_monitoring.detailed_performance_tracking", "help": "Enable detailed performance tracking"},
|
|
573
|
+
{"type": "checkbox", "label": "Enable Health Dashboard", "config_path": "plugins.hook_monitoring.enable_health_dashboard", "help": "Show health monitoring dashboard"},
|
|
574
|
+
{"type": "slider", "label": "Dashboard Update Interval", "config_path": "plugins.hook_monitoring.dashboard_update_interval", "min_value": 1, "max_value": 60, "step": 1, "help": "Dashboard refresh interval in seconds"},
|
|
575
|
+
{"type": "checkbox", "label": "Show Plugin Interactions", "config_path": "plugins.hook_monitoring.show_plugin_interactions", "help": "Display plugin interaction information"},
|
|
576
|
+
{"type": "checkbox", "label": "Show Service Usage", "config_path": "plugins.hook_monitoring.show_service_usage", "help": "Display service usage statistics"}
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
def _create_all_hooks(self) -> List[Hook]:
|
|
581
|
+
"""[TOOL] SHOWCASE: Create comprehensive hooks for monitoring all event types.
|
|
582
|
+
|
|
583
|
+
This demonstrates complete system monitoring by hooking into all
|
|
584
|
+
available event types to provide full visibility into system behavior.
|
|
585
|
+
|
|
586
|
+
Returns:
|
|
587
|
+
List of hooks covering all event types for comprehensive monitoring.
|
|
588
|
+
"""
|
|
589
|
+
hooks = []
|
|
590
|
+
timeout = self.config.get('plugins.hook_monitoring.hook_timeout', 5)
|
|
591
|
+
|
|
592
|
+
# User input events
|
|
593
|
+
hooks.extend([
|
|
594
|
+
Hook(
|
|
595
|
+
name="monitor_user_input_pre",
|
|
596
|
+
plugin_name=self.name,
|
|
597
|
+
event_type=EventType.USER_INPUT_PRE,
|
|
598
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
599
|
+
callback=self._log_hook_execution,
|
|
600
|
+
timeout=timeout
|
|
601
|
+
),
|
|
602
|
+
Hook(
|
|
603
|
+
name="monitor_user_input",
|
|
604
|
+
plugin_name=self.name,
|
|
605
|
+
event_type=EventType.USER_INPUT,
|
|
606
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
607
|
+
callback=self._log_hook_execution,
|
|
608
|
+
timeout=timeout
|
|
609
|
+
),
|
|
610
|
+
Hook(
|
|
611
|
+
name="monitor_user_input_post",
|
|
612
|
+
plugin_name=self.name,
|
|
613
|
+
event_type=EventType.USER_INPUT_POST,
|
|
614
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
615
|
+
callback=self._log_hook_execution,
|
|
616
|
+
timeout=timeout
|
|
617
|
+
)
|
|
618
|
+
])
|
|
619
|
+
|
|
620
|
+
# Key press events
|
|
621
|
+
hooks.extend([
|
|
622
|
+
Hook(
|
|
623
|
+
name="test_key_press_pre",
|
|
624
|
+
plugin_name=self.name,
|
|
625
|
+
event_type=EventType.KEY_PRESS_PRE,
|
|
626
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
627
|
+
callback=self._log_hook_execution,
|
|
628
|
+
timeout=timeout
|
|
629
|
+
),
|
|
630
|
+
Hook(
|
|
631
|
+
name="test_key_press",
|
|
632
|
+
plugin_name=self.name,
|
|
633
|
+
event_type=EventType.KEY_PRESS,
|
|
634
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
635
|
+
callback=self._log_hook_execution,
|
|
636
|
+
timeout=timeout
|
|
637
|
+
),
|
|
638
|
+
Hook(
|
|
639
|
+
name="test_key_press_post",
|
|
640
|
+
plugin_name=self.name,
|
|
641
|
+
event_type=EventType.KEY_PRESS_POST,
|
|
642
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
643
|
+
callback=self._log_hook_execution,
|
|
644
|
+
timeout=timeout
|
|
645
|
+
)
|
|
646
|
+
])
|
|
647
|
+
|
|
648
|
+
# Paste events
|
|
649
|
+
hooks.append(
|
|
650
|
+
Hook(
|
|
651
|
+
name="test_paste_detected",
|
|
652
|
+
plugin_name=self.name,
|
|
653
|
+
event_type=EventType.PASTE_DETECTED,
|
|
654
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
655
|
+
callback=self._log_hook_execution,
|
|
656
|
+
timeout=timeout
|
|
657
|
+
)
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
# LLM events
|
|
661
|
+
hooks.extend([
|
|
662
|
+
Hook(
|
|
663
|
+
name="test_llm_request_pre",
|
|
664
|
+
plugin_name=self.name,
|
|
665
|
+
event_type=EventType.LLM_REQUEST_PRE,
|
|
666
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
667
|
+
callback=self._log_hook_execution,
|
|
668
|
+
timeout=timeout
|
|
669
|
+
),
|
|
670
|
+
Hook(
|
|
671
|
+
name="test_llm_request",
|
|
672
|
+
plugin_name=self.name,
|
|
673
|
+
event_type=EventType.LLM_REQUEST,
|
|
674
|
+
priority=HookPriority.LLM.value,
|
|
675
|
+
callback=self._log_hook_execution,
|
|
676
|
+
timeout=timeout
|
|
677
|
+
),
|
|
678
|
+
Hook(
|
|
679
|
+
name="test_llm_request_post",
|
|
680
|
+
plugin_name=self.name,
|
|
681
|
+
event_type=EventType.LLM_REQUEST_POST,
|
|
682
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
683
|
+
callback=self._log_hook_execution,
|
|
684
|
+
timeout=timeout
|
|
685
|
+
),
|
|
686
|
+
Hook(
|
|
687
|
+
name="test_llm_response_pre",
|
|
688
|
+
plugin_name=self.name,
|
|
689
|
+
event_type=EventType.LLM_RESPONSE_PRE,
|
|
690
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
691
|
+
callback=self._log_hook_execution,
|
|
692
|
+
timeout=timeout
|
|
693
|
+
),
|
|
694
|
+
Hook(
|
|
695
|
+
name="test_llm_response",
|
|
696
|
+
plugin_name=self.name,
|
|
697
|
+
event_type=EventType.LLM_RESPONSE,
|
|
698
|
+
priority=HookPriority.LLM.value,
|
|
699
|
+
callback=self._log_hook_execution,
|
|
700
|
+
timeout=timeout
|
|
701
|
+
),
|
|
702
|
+
Hook(
|
|
703
|
+
name="test_llm_response_post",
|
|
704
|
+
plugin_name=self.name,
|
|
705
|
+
event_type=EventType.LLM_RESPONSE_POST,
|
|
706
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
707
|
+
callback=self._log_hook_execution,
|
|
708
|
+
timeout=timeout
|
|
709
|
+
),
|
|
710
|
+
Hook(
|
|
711
|
+
name="test_llm_thinking",
|
|
712
|
+
plugin_name=self.name,
|
|
713
|
+
event_type=EventType.LLM_THINKING,
|
|
714
|
+
priority=HookPriority.LLM.value,
|
|
715
|
+
callback=self._log_hook_execution,
|
|
716
|
+
timeout=timeout
|
|
717
|
+
),
|
|
718
|
+
Hook(
|
|
719
|
+
name="test_cancel_request",
|
|
720
|
+
plugin_name=self.name,
|
|
721
|
+
event_type=EventType.CANCEL_REQUEST,
|
|
722
|
+
priority=HookPriority.LLM.value,
|
|
723
|
+
callback=self._log_hook_execution,
|
|
724
|
+
timeout=timeout
|
|
725
|
+
)
|
|
726
|
+
])
|
|
727
|
+
|
|
728
|
+
# Tool events
|
|
729
|
+
hooks.extend([
|
|
730
|
+
Hook(
|
|
731
|
+
name="test_tool_call_pre",
|
|
732
|
+
plugin_name=self.name,
|
|
733
|
+
event_type=EventType.TOOL_CALL_PRE,
|
|
734
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
735
|
+
callback=self._log_hook_execution,
|
|
736
|
+
timeout=timeout
|
|
737
|
+
),
|
|
738
|
+
Hook(
|
|
739
|
+
name="test_tool_call",
|
|
740
|
+
plugin_name=self.name,
|
|
741
|
+
event_type=EventType.TOOL_CALL,
|
|
742
|
+
priority=HookPriority.LLM.value,
|
|
743
|
+
callback=self._log_hook_execution,
|
|
744
|
+
timeout=timeout
|
|
745
|
+
),
|
|
746
|
+
Hook(
|
|
747
|
+
name="test_tool_call_post",
|
|
748
|
+
plugin_name=self.name,
|
|
749
|
+
event_type=EventType.TOOL_CALL_POST,
|
|
750
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
751
|
+
callback=self._log_hook_execution,
|
|
752
|
+
timeout=timeout
|
|
753
|
+
)
|
|
754
|
+
])
|
|
755
|
+
|
|
756
|
+
# System events
|
|
757
|
+
hooks.extend([
|
|
758
|
+
Hook(
|
|
759
|
+
name="test_system_startup",
|
|
760
|
+
plugin_name=self.name,
|
|
761
|
+
event_type=EventType.SYSTEM_STARTUP,
|
|
762
|
+
priority=HookPriority.SYSTEM.value,
|
|
763
|
+
callback=self._log_hook_execution,
|
|
764
|
+
timeout=timeout
|
|
765
|
+
),
|
|
766
|
+
Hook(
|
|
767
|
+
name="test_system_shutdown",
|
|
768
|
+
plugin_name=self.name,
|
|
769
|
+
event_type=EventType.SYSTEM_SHUTDOWN,
|
|
770
|
+
priority=HookPriority.SYSTEM.value,
|
|
771
|
+
callback=self._log_hook_execution,
|
|
772
|
+
timeout=timeout
|
|
773
|
+
),
|
|
774
|
+
Hook(
|
|
775
|
+
name="test_render_frame",
|
|
776
|
+
plugin_name=self.name,
|
|
777
|
+
event_type=EventType.RENDER_FRAME,
|
|
778
|
+
priority=HookPriority.DISPLAY.value,
|
|
779
|
+
callback=self._log_hook_execution,
|
|
780
|
+
timeout=timeout
|
|
781
|
+
)
|
|
782
|
+
])
|
|
783
|
+
|
|
784
|
+
# Input rendering events
|
|
785
|
+
hooks.extend([
|
|
786
|
+
Hook(
|
|
787
|
+
name="test_input_render_pre",
|
|
788
|
+
plugin_name=self.name,
|
|
789
|
+
event_type=EventType.INPUT_RENDER_PRE,
|
|
790
|
+
priority=HookPriority.PREPROCESSING.value,
|
|
791
|
+
callback=self._log_hook_execution,
|
|
792
|
+
timeout=timeout
|
|
793
|
+
),
|
|
794
|
+
Hook(
|
|
795
|
+
name="test_input_render",
|
|
796
|
+
plugin_name=self.name,
|
|
797
|
+
event_type=EventType.INPUT_RENDER,
|
|
798
|
+
priority=HookPriority.DISPLAY.value,
|
|
799
|
+
callback=self._log_hook_execution,
|
|
800
|
+
timeout=timeout
|
|
801
|
+
),
|
|
802
|
+
Hook(
|
|
803
|
+
name="test_input_render_post",
|
|
804
|
+
plugin_name=self.name,
|
|
805
|
+
event_type=EventType.INPUT_RENDER_POST,
|
|
806
|
+
priority=HookPriority.POSTPROCESSING.value,
|
|
807
|
+
callback=self._log_hook_execution,
|
|
808
|
+
timeout=timeout
|
|
809
|
+
)
|
|
810
|
+
])
|
|
811
|
+
|
|
812
|
+
# Command menu events
|
|
813
|
+
hooks.extend([
|
|
814
|
+
Hook(
|
|
815
|
+
name="test_command_menu_show",
|
|
816
|
+
plugin_name=self.name,
|
|
817
|
+
event_type=EventType.COMMAND_MENU_SHOW,
|
|
818
|
+
priority=HookPriority.DISPLAY.value,
|
|
819
|
+
callback=self._log_hook_execution,
|
|
820
|
+
timeout=timeout
|
|
821
|
+
),
|
|
822
|
+
Hook(
|
|
823
|
+
name="test_command_menu_navigate",
|
|
824
|
+
plugin_name=self.name,
|
|
825
|
+
event_type=EventType.COMMAND_MENU_NAVIGATE,
|
|
826
|
+
priority=HookPriority.DISPLAY.value,
|
|
827
|
+
callback=self._log_hook_execution,
|
|
828
|
+
timeout=timeout
|
|
829
|
+
),
|
|
830
|
+
Hook(
|
|
831
|
+
name="test_command_menu_select",
|
|
832
|
+
plugin_name=self.name,
|
|
833
|
+
event_type=EventType.COMMAND_MENU_SELECT,
|
|
834
|
+
priority=HookPriority.DISPLAY.value,
|
|
835
|
+
callback=self._log_hook_execution,
|
|
836
|
+
timeout=timeout
|
|
837
|
+
),
|
|
838
|
+
Hook(
|
|
839
|
+
name="test_command_menu_hide",
|
|
840
|
+
plugin_name=self.name,
|
|
841
|
+
event_type=EventType.COMMAND_MENU_HIDE,
|
|
842
|
+
priority=HookPriority.DISPLAY.value,
|
|
843
|
+
callback=self._log_hook_execution,
|
|
844
|
+
timeout=timeout
|
|
845
|
+
)
|
|
846
|
+
])
|
|
847
|
+
|
|
848
|
+
logger.info(f"Hook Monitor: Created {len(hooks)} monitoring hooks for system health tracking")
|
|
849
|
+
return hooks
|
|
850
|
+
|
|
851
|
+
# [TOOL] SERVICE IMPLEMENTATION METHODS - These are called by other plugins via SDK
|
|
852
|
+
|
|
853
|
+
async def _provide_performance_monitoring(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
854
|
+
"""[TOOL] SHOWCASE: Performance monitoring service for other plugins.
|
|
855
|
+
|
|
856
|
+
This service can be called by other plugins like:
|
|
857
|
+
result = await sdk.execute_custom_tool("monitor_performance", {
|
|
858
|
+
"plugin_name": "EnhancedInputPlugin",
|
|
859
|
+
"metric_type": "execution_time"
|
|
860
|
+
})
|
|
861
|
+
"""
|
|
862
|
+
plugin_name = params.get("plugin_name", "all")
|
|
863
|
+
metric_type = params.get("metric_type", "summary")
|
|
864
|
+
|
|
865
|
+
logger.info(f"[DATA] Performance monitoring requested for {plugin_name}, metric: {metric_type}")
|
|
866
|
+
|
|
867
|
+
if plugin_name == "all":
|
|
868
|
+
# Return performance data for all plugins
|
|
869
|
+
return {
|
|
870
|
+
"status": "success",
|
|
871
|
+
"data": {
|
|
872
|
+
"total_executions": self.hook_executions,
|
|
873
|
+
"performance_metrics": self.hook_performance,
|
|
874
|
+
"health_status": self.hook_health_status,
|
|
875
|
+
"timestamp": datetime.datetime.now().isoformat()
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else:
|
|
879
|
+
# Return specific plugin performance
|
|
880
|
+
plugin_perf = self.plugin_health_stats.get(plugin_name, {})
|
|
881
|
+
return {
|
|
882
|
+
"status": "success",
|
|
883
|
+
"data": {
|
|
884
|
+
"plugin_name": plugin_name,
|
|
885
|
+
"performance": plugin_perf,
|
|
886
|
+
"timestamp": datetime.datetime.now().isoformat()
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async def _provide_health_check(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
891
|
+
"""[HEALTH] SHOWCASE: Health check service for other plugins.
|
|
892
|
+
|
|
893
|
+
Other plugins can call this to check system health:
|
|
894
|
+
health = await sdk.execute_custom_tool("check_plugin_health", {
|
|
895
|
+
"plugin_name": "system",
|
|
896
|
+
"detailed": True
|
|
897
|
+
})
|
|
898
|
+
"""
|
|
899
|
+
plugin_name = params.get("plugin_name", "system")
|
|
900
|
+
detailed = params.get("detailed", False)
|
|
901
|
+
|
|
902
|
+
logger.info(f"[HEALTH] Health check requested for {plugin_name}, detailed: {detailed}")
|
|
903
|
+
|
|
904
|
+
if plugin_name == "system":
|
|
905
|
+
# System-wide health check
|
|
906
|
+
failure_rate = 0
|
|
907
|
+
if self.hook_executions > 0:
|
|
908
|
+
failure_rate = (self.failed_hooks + self.timeout_hooks) / self.hook_executions
|
|
909
|
+
|
|
910
|
+
health_data = {
|
|
911
|
+
"overall_health": self.hook_health_status,
|
|
912
|
+
"failure_rate": failure_rate,
|
|
913
|
+
"total_plugins": len(self.discovered_plugins),
|
|
914
|
+
"active_plugins": len([p for p in self.plugin_health_stats.values() if p.get("status") == "active"])
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
if detailed:
|
|
918
|
+
health_data.update({
|
|
919
|
+
"plugin_details": self.plugin_health_stats,
|
|
920
|
+
"recent_errors": self.error_log[-5:] if self.error_log else [],
|
|
921
|
+
"performance_summary": self.hook_performance
|
|
922
|
+
})
|
|
923
|
+
|
|
924
|
+
return {"status": "success", "health": health_data}
|
|
925
|
+
else:
|
|
926
|
+
# Specific plugin health check
|
|
927
|
+
plugin_health = self.plugin_health_stats.get(plugin_name, {"status": "unknown"})
|
|
928
|
+
return {"status": "success", "health": plugin_health}
|
|
929
|
+
|
|
930
|
+
async def _provide_metrics_collection(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
931
|
+
"""[METRICS] SHOWCASE: Metrics collection service for analytics.
|
|
932
|
+
|
|
933
|
+
Other plugins can request comprehensive metrics:
|
|
934
|
+
metrics = await sdk.execute_custom_tool("collect_system_metrics", {
|
|
935
|
+
"time_range": "last_hour",
|
|
936
|
+
"include_performance": True
|
|
937
|
+
})
|
|
938
|
+
"""
|
|
939
|
+
time_range = params.get("time_range", "current")
|
|
940
|
+
include_performance = params.get("include_performance", True)
|
|
941
|
+
|
|
942
|
+
logger.info(f"[METRICS] Metrics collection requested for {time_range}, performance: {include_performance}")
|
|
943
|
+
|
|
944
|
+
metrics = {
|
|
945
|
+
"collection_timestamp": datetime.datetime.now().isoformat(),
|
|
946
|
+
"time_range": time_range,
|
|
947
|
+
"system_metrics": {
|
|
948
|
+
"total_hook_executions": self.hook_executions,
|
|
949
|
+
"failed_hooks": self.failed_hooks,
|
|
950
|
+
"timeout_hooks": self.timeout_hooks,
|
|
951
|
+
"health_status": self.hook_health_status,
|
|
952
|
+
"discovered_plugins": len(self.discovered_plugins),
|
|
953
|
+
"active_services": len(self.available_services)
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if include_performance:
|
|
958
|
+
metrics["performance_metrics"] = self.hook_performance
|
|
959
|
+
|
|
960
|
+
return {"status": "success", "metrics": metrics}
|
|
961
|
+
|
|
962
|
+
# [COMM] CROSS-PLUGIN COMMUNICATION HANDLERS
|
|
963
|
+
|
|
964
|
+
async def _handle_health_check_request(self, message: Dict[str, Any], sender: str) -> None:
|
|
965
|
+
"""[COMM] SHOWCASE: Handle health check requests from other plugins.
|
|
966
|
+
|
|
967
|
+
This demonstrates direct plugin-to-plugin communication.
|
|
968
|
+
"""
|
|
969
|
+
logger.info(f"[COMM] Health check request received from {sender}")
|
|
970
|
+
|
|
971
|
+
# Record the communication
|
|
972
|
+
self.cross_plugin_messages.append({
|
|
973
|
+
"timestamp": datetime.datetime.now(),
|
|
974
|
+
"sender": sender,
|
|
975
|
+
"message_type": "health_check_request",
|
|
976
|
+
"data": message
|
|
977
|
+
})
|
|
978
|
+
|
|
979
|
+
# Keep message history limited
|
|
980
|
+
if len(self.cross_plugin_messages) > self.message_history_limit:
|
|
981
|
+
self.cross_plugin_messages = self.cross_plugin_messages[-self.message_history_limit:]
|
|
982
|
+
|
|
983
|
+
# Update sender's plugin stats
|
|
984
|
+
if sender in self.plugin_health_stats:
|
|
985
|
+
self.plugin_health_stats[sender]["message_count"] += 1
|
|
986
|
+
self.plugin_health_stats[sender]["last_seen"] = datetime.datetime.now()
|
|
987
|
+
|
|
988
|
+
async def _handle_performance_data_request(self, message: Dict[str, Any], sender: str) -> Dict[str, Any]:
|
|
989
|
+
"""[COMM] SHOWCASE: Handle performance data requests from other plugins."""
|
|
990
|
+
logger.info(f"[DATA] Performance data request from {sender}")
|
|
991
|
+
|
|
992
|
+
# This would typically send data back via event bus
|
|
993
|
+
performance_data = {
|
|
994
|
+
"hook_executions": self.hook_executions,
|
|
995
|
+
"performance_metrics": self.hook_performance,
|
|
996
|
+
"timestamp": datetime.datetime.now().isoformat()
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
return performance_data
|
|
1000
|
+
|
|
1001
|
+
async def _handle_plugin_status_update(self, message: Dict[str, Any], sender: str) -> None:
|
|
1002
|
+
"""[COMM] SHOWCASE: Handle status updates from other plugins."""
|
|
1003
|
+
logger.info(f"[CLIP] Status update received from {sender}")
|
|
1004
|
+
|
|
1005
|
+
# Update our records about the sender plugin
|
|
1006
|
+
if sender not in self.plugin_health_stats:
|
|
1007
|
+
self.plugin_health_stats[sender] = {}
|
|
1008
|
+
|
|
1009
|
+
self.plugin_health_stats[sender].update({
|
|
1010
|
+
"last_status_update": datetime.datetime.now(),
|
|
1011
|
+
"reported_status": message.get("status", "unknown"),
|
|
1012
|
+
"additional_data": message.get("data", {})
|
|
1013
|
+
})
|
|
1014
|
+
|
|
1015
|
+
async def _log_hook_execution(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
|
|
1016
|
+
"""Log hook execution details.
|
|
1017
|
+
|
|
1018
|
+
Args:
|
|
1019
|
+
data: Event data.
|
|
1020
|
+
event: Event object.
|
|
1021
|
+
|
|
1022
|
+
Returns:
|
|
1023
|
+
Hook result with logging information.
|
|
1024
|
+
"""
|
|
1025
|
+
self.hook_executions += 1
|
|
1026
|
+
self.last_hook_event = event.type.value
|
|
1027
|
+
|
|
1028
|
+
start_time = time.time()
|
|
1029
|
+
|
|
1030
|
+
# Update performance tracking
|
|
1031
|
+
self._update_performance_metrics(event.type.value, start_time)
|
|
1032
|
+
|
|
1033
|
+
# Determine if this should be logged based on configuration
|
|
1034
|
+
log_all = self.config.get('plugins.hook_monitoring.log_all_events', True)
|
|
1035
|
+
log_failures_only = self.config.get('plugins.hook_monitoring.log_failures_only', False)
|
|
1036
|
+
|
|
1037
|
+
if log_all and not log_failures_only:
|
|
1038
|
+
# Filter out excessive render and key press events to reduce log spam
|
|
1039
|
+
if event.type.value not in ['input_render', 'render', 'key_press', 'key_press_pre', 'key_press_post']:
|
|
1040
|
+
logger.debug(f"HOOK MONITOR [{self.hook_executions}]: {event.type.value} from {event.source}")
|
|
1041
|
+
|
|
1042
|
+
# Log event data if configured
|
|
1043
|
+
if self.config.get('plugins.hook_monitoring.log_event_data', False):
|
|
1044
|
+
logger.debug(f"Hook Monitor - Event data keys: {list(data.keys()) if isinstance(data, dict) else type(data).__name__}")
|
|
1045
|
+
|
|
1046
|
+
# Check for performance issues
|
|
1047
|
+
execution_time_ms = (time.time() - start_time) * 1000
|
|
1048
|
+
threshold_ms = self.config.get('plugins.hook_monitoring.performance_threshold_ms', 100)
|
|
1049
|
+
|
|
1050
|
+
if execution_time_ms > threshold_ms:
|
|
1051
|
+
logger.warning(f"Hook Monitor - SLOW HOOK: {event.type.value} took {execution_time_ms:.1f}ms (threshold: {threshold_ms}ms)")
|
|
1052
|
+
|
|
1053
|
+
# Update health status
|
|
1054
|
+
self._update_health_status()
|
|
1055
|
+
|
|
1056
|
+
return {
|
|
1057
|
+
"status": "monitored",
|
|
1058
|
+
"execution_count": self.hook_executions,
|
|
1059
|
+
"event_type": event.type.value,
|
|
1060
|
+
"plugin_name": self.name,
|
|
1061
|
+
"execution_time_ms": execution_time_ms,
|
|
1062
|
+
"health_status": self.hook_health_status
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
def _update_performance_metrics(self, event_type: str, start_time: float) -> None:
|
|
1066
|
+
"""Update performance metrics for hook monitoring.
|
|
1067
|
+
|
|
1068
|
+
Args:
|
|
1069
|
+
event_type: The event type being monitored.
|
|
1070
|
+
start_time: Start time of the hook execution.
|
|
1071
|
+
"""
|
|
1072
|
+
execution_time = (time.time() - start_time) * 1000 # Convert to milliseconds
|
|
1073
|
+
|
|
1074
|
+
if event_type not in self.hook_performance:
|
|
1075
|
+
self.hook_performance[event_type] = {
|
|
1076
|
+
"total_time": 0,
|
|
1077
|
+
"count": 0,
|
|
1078
|
+
"avg_time": 0,
|
|
1079
|
+
"max_time": 0,
|
|
1080
|
+
"min_time": float('inf')
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
metrics = self.hook_performance[event_type]
|
|
1084
|
+
metrics["total_time"] += execution_time
|
|
1085
|
+
metrics["count"] += 1
|
|
1086
|
+
metrics["avg_time"] = metrics["total_time"] / metrics["count"]
|
|
1087
|
+
metrics["max_time"] = max(metrics["max_time"], execution_time)
|
|
1088
|
+
metrics["min_time"] = min(metrics["min_time"], execution_time)
|
|
1089
|
+
|
|
1090
|
+
def _update_health_status(self) -> None:
|
|
1091
|
+
"""Update the overall health status of the hook system."""
|
|
1092
|
+
total_hooks = self.hook_executions
|
|
1093
|
+
if total_hooks == 0:
|
|
1094
|
+
self.hook_health_status = "Starting"
|
|
1095
|
+
return
|
|
1096
|
+
|
|
1097
|
+
failure_rate = (self.failed_hooks + self.timeout_hooks) / total_hooks
|
|
1098
|
+
|
|
1099
|
+
if failure_rate == 0:
|
|
1100
|
+
self.hook_health_status = "Healthy"
|
|
1101
|
+
elif failure_rate < self.config.get("performance.failure_rate_warning", 0.05):
|
|
1102
|
+
self.hook_health_status = "Good"
|
|
1103
|
+
elif failure_rate < self.config.get("performance.failure_rate_critical", 0.15):
|
|
1104
|
+
self.hook_health_status = "Warning"
|
|
1105
|
+
else:
|
|
1106
|
+
self.hook_health_status = "Critical"
|
|
1107
|
+
|
|
1108
|
+
def _log_error(self, error_msg: str, event_type: str) -> None:
|
|
1109
|
+
"""Log an error with rotation to prevent memory bloat.
|
|
1110
|
+
|
|
1111
|
+
Args:
|
|
1112
|
+
error_msg: Error message to log.
|
|
1113
|
+
event_type: Event type where error occurred.
|
|
1114
|
+
"""
|
|
1115
|
+
error_entry = {
|
|
1116
|
+
"timestamp": datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3],
|
|
1117
|
+
"event_type": event_type,
|
|
1118
|
+
"message": error_msg
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
self.error_log.append(error_entry)
|
|
1122
|
+
|
|
1123
|
+
# Rotate error log to prevent memory bloat
|
|
1124
|
+
max_size = self.config.get('plugins.hook_monitoring.max_error_log_size', 50)
|
|
1125
|
+
if len(self.error_log) > max_size:
|
|
1126
|
+
self.error_log = self.error_log[-max_size:]
|
|
1127
|
+
|
|
1128
|
+
def _log_final_report(self) -> None:
|
|
1129
|
+
"""Log a comprehensive final report of hook monitoring."""
|
|
1130
|
+
if not self.config.get('plugins.hook_monitoring.log_performance', True):
|
|
1131
|
+
return
|
|
1132
|
+
|
|
1133
|
+
logger.info("=== HOOK MONITOR FINAL REPORT ===")
|
|
1134
|
+
logger.info(f"Total Hook Executions: {self.hook_executions}")
|
|
1135
|
+
logger.info(f"Failed Hooks: {self.failed_hooks}")
|
|
1136
|
+
logger.info(f"Timeout Hooks: {self.timeout_hooks}")
|
|
1137
|
+
logger.info(f"Final Health Status: {self.hook_health_status}")
|
|
1138
|
+
|
|
1139
|
+
if self.hook_performance:
|
|
1140
|
+
logger.info("=== PERFORMANCE METRICS ===")
|
|
1141
|
+
for event_type, metrics in self.hook_performance.items():
|
|
1142
|
+
if metrics["count"] > 0:
|
|
1143
|
+
logger.info(f"{event_type}: {metrics['count']} executions, "
|
|
1144
|
+
f"avg: {metrics['avg_time']:.1f}ms, "
|
|
1145
|
+
f"max: {metrics['max_time']:.1f}ms, "
|
|
1146
|
+
f"min: {metrics['min_time']:.1f}ms")
|
|
1147
|
+
|
|
1148
|
+
if self.error_log:
|
|
1149
|
+
logger.info("=== RECENT ERRORS ===")
|
|
1150
|
+
for error in self.error_log[-10:]: # Show last 10 errors
|
|
1151
|
+
logger.info(f"[{error['timestamp']}] {error['event_type']}: {error['message']}")
|
|
1152
|
+
|
|
1153
|
+
logger.info("=== END HOOK MONITOR REPORT ===")
|
|
1154
|
+
|
|
1155
|
+
def get_monitoring_stats(self) -> Dict[str, Any]:
|
|
1156
|
+
"""Get current monitoring statistics.
|
|
1157
|
+
|
|
1158
|
+
Returns:
|
|
1159
|
+
Dictionary with comprehensive monitoring statistics.
|
|
1160
|
+
"""
|
|
1161
|
+
return {
|
|
1162
|
+
"total_executions": self.hook_executions,
|
|
1163
|
+
"failed_hooks": self.failed_hooks,
|
|
1164
|
+
"timeout_hooks": self.timeout_hooks,
|
|
1165
|
+
"health_status": self.hook_health_status,
|
|
1166
|
+
"last_event": self.last_hook_event,
|
|
1167
|
+
"performance_metrics": self.hook_performance,
|
|
1168
|
+
"recent_errors": self.error_log[-5:] if self.error_log else [],
|
|
1169
|
+
"failure_rate": (self.failed_hooks + self.timeout_hooks) / max(1, self.hook_executions)
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
# [TARGET] PUBLIC API METHODS - For other plugins to use
|
|
1173
|
+
|
|
1174
|
+
def get_plugin_ecosystem_dashboard(self) -> Dict[str, Any]:
|
|
1175
|
+
"""[TARGET] SHOWCASE: Public API - Plugin Ecosystem Dashboard.
|
|
1176
|
+
|
|
1177
|
+
This method can be called by other plugins to get a comprehensive
|
|
1178
|
+
view of the entire plugin ecosystem. Perfect demonstration of how
|
|
1179
|
+
plugins can provide services to each other!
|
|
1180
|
+
|
|
1181
|
+
Example usage from another plugin:
|
|
1182
|
+
```python
|
|
1183
|
+
# Get the hook monitoring plugin instance
|
|
1184
|
+
factory = self.get_factory()
|
|
1185
|
+
monitor = factory.get_instance("HookMonitoringPlugin")
|
|
1186
|
+
|
|
1187
|
+
# Get ecosystem dashboard
|
|
1188
|
+
dashboard = monitor.get_plugin_ecosystem_dashboard()
|
|
1189
|
+
print(f"Total plugins: {dashboard['summary']['total_plugins']}")
|
|
1190
|
+
```
|
|
1191
|
+
"""
|
|
1192
|
+
# Calculate comprehensive ecosystem metrics
|
|
1193
|
+
total_plugins = len(getattr(self, 'discovered_plugins', {}))
|
|
1194
|
+
active_plugins = len([p for p in getattr(self, 'plugin_health_stats', {}).values()
|
|
1195
|
+
if p.get("status") != "error"])
|
|
1196
|
+
|
|
1197
|
+
failure_rate = 0
|
|
1198
|
+
if self.hook_executions > 0:
|
|
1199
|
+
failure_rate = (self.failed_hooks + self.timeout_hooks) / self.hook_executions
|
|
1200
|
+
|
|
1201
|
+
dashboard = {
|
|
1202
|
+
"[TARGET] PLUGIN ECOSYSTEM DASHBOARD": "Live Status",
|
|
1203
|
+
|
|
1204
|
+
"summary": {
|
|
1205
|
+
"total_plugins": total_plugins,
|
|
1206
|
+
"active_plugins": active_plugins,
|
|
1207
|
+
"registered_services": 3 if (self.service_registration_enabled and SDK_AVAILABLE) else 0,
|
|
1208
|
+
"system_health": self.hook_health_status,
|
|
1209
|
+
"overall_failure_rate": failure_rate,
|
|
1210
|
+
"last_updated": datetime.datetime.now().isoformat()
|
|
1211
|
+
},
|
|
1212
|
+
|
|
1213
|
+
"hook_monitoring": {
|
|
1214
|
+
"total_executions": self.hook_executions,
|
|
1215
|
+
"failed_hooks": self.failed_hooks,
|
|
1216
|
+
"timeout_hooks": self.timeout_hooks,
|
|
1217
|
+
"performance_metrics": dict(list(self.hook_performance.items())[:5]) # Top 5
|
|
1218
|
+
},
|
|
1219
|
+
|
|
1220
|
+
"plugin_discovery": {
|
|
1221
|
+
"discovery_enabled": self.plugin_discovery_enabled,
|
|
1222
|
+
"discovered_plugins": list(getattr(self, 'discovered_plugins', {}).keys()),
|
|
1223
|
+
"plugin_capabilities": getattr(self, 'plugin_health_stats', {})
|
|
1224
|
+
},
|
|
1225
|
+
|
|
1226
|
+
"service_registration": {
|
|
1227
|
+
"sdk_available": SDK_AVAILABLE,
|
|
1228
|
+
"services_enabled": self.service_registration_enabled,
|
|
1229
|
+
"available_services": [
|
|
1230
|
+
"monitor_performance",
|
|
1231
|
+
"check_plugin_health",
|
|
1232
|
+
"collect_system_metrics"
|
|
1233
|
+
] if (self.service_registration_enabled and SDK_AVAILABLE) else []
|
|
1234
|
+
},
|
|
1235
|
+
|
|
1236
|
+
"cross_plugin_communication": {
|
|
1237
|
+
"communication_enabled": self.enable_cross_plugin_comm,
|
|
1238
|
+
"recent_messages": len(getattr(self, 'cross_plugin_messages', [])),
|
|
1239
|
+
"message_history": getattr(self, 'cross_plugin_messages', [])[-3:], # Last 3
|
|
1240
|
+
"message_handlers": list(getattr(self, 'message_handlers', {}).keys())
|
|
1241
|
+
},
|
|
1242
|
+
|
|
1243
|
+
"showcase_features": {
|
|
1244
|
+
"[FIND] Plugin Discovery": "[OK] Active" if self.plugin_discovery_enabled else "Disabled",
|
|
1245
|
+
"[TOOL] Service Registration": "[OK] Active" if (self.service_registration_enabled and SDK_AVAILABLE) else "Disabled",
|
|
1246
|
+
"[COMM] Cross-Plugin Comm": "[OK] Active" if self.enable_cross_plugin_comm else "Disabled",
|
|
1247
|
+
"[DATA] Performance Monitoring": "[OK] Active",
|
|
1248
|
+
"[HEALTH] Health Monitoring": "[OK] Active",
|
|
1249
|
+
"[METRICS] Metrics Collection": "[OK] Active"
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
return dashboard
|
|
1254
|
+
|
|
1255
|
+
async def send_demo_message_to_plugin(self, target_plugin: str, message_type: str = "demo") -> Dict[str, Any]:
|
|
1256
|
+
"""[COMM] SHOWCASE: Send a demonstration message to another plugin.
|
|
1257
|
+
|
|
1258
|
+
This showcases cross-plugin communication patterns.
|
|
1259
|
+
|
|
1260
|
+
Args:
|
|
1261
|
+
target_plugin: Name of the plugin to send message to
|
|
1262
|
+
message_type: Type of message to send
|
|
1263
|
+
|
|
1264
|
+
Returns:
|
|
1265
|
+
Result of the message sending attempt
|
|
1266
|
+
"""
|
|
1267
|
+
logger.info(f"[COMM] DEMO: Sending {message_type} message to {target_plugin}")
|
|
1268
|
+
|
|
1269
|
+
demo_message = {
|
|
1270
|
+
"sender": self.name,
|
|
1271
|
+
"message_type": message_type,
|
|
1272
|
+
"timestamp": datetime.datetime.now().isoformat(),
|
|
1273
|
+
"data": {
|
|
1274
|
+
"demo": True,
|
|
1275
|
+
"system_health": self.hook_health_status,
|
|
1276
|
+
"hook_executions": self.hook_executions,
|
|
1277
|
+
"message": f"Hello from {self.name}! This demonstrates cross-plugin communication."
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
# Record the outgoing message
|
|
1282
|
+
if hasattr(self, 'cross_plugin_messages'):
|
|
1283
|
+
self.cross_plugin_messages.append({
|
|
1284
|
+
"timestamp": datetime.datetime.now(),
|
|
1285
|
+
"direction": "outgoing",
|
|
1286
|
+
"target": target_plugin,
|
|
1287
|
+
"message_type": message_type,
|
|
1288
|
+
"data": demo_message
|
|
1289
|
+
})
|
|
1290
|
+
|
|
1291
|
+
# In a real implementation, this would use the event bus:
|
|
1292
|
+
# await self.event_bus.send_message(target_plugin=target_plugin, data=demo_message)
|
|
1293
|
+
|
|
1294
|
+
return {
|
|
1295
|
+
"status": "demo_sent",
|
|
1296
|
+
"target": target_plugin,
|
|
1297
|
+
"message": demo_message,
|
|
1298
|
+
"note": "In production, this would use the event bus for actual delivery"
|
|
1299
|
+
}
|