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
core/logging/setup.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Centralized logging configuration and setup.
|
|
2
|
+
|
|
3
|
+
This module handles all logging configuration for the application,
|
|
4
|
+
reading from the config system when available and providing sensible
|
|
5
|
+
defaults during bootstrap.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import logging.handlers
|
|
10
|
+
import threading
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CompactFormatter(logging.Formatter):
|
|
16
|
+
"""Custom formatter that compacts level names and includes file location."""
|
|
17
|
+
|
|
18
|
+
def format(self, record):
|
|
19
|
+
# Map long level names to 4-char versions
|
|
20
|
+
level_mapping = {
|
|
21
|
+
'WARNING': 'WARN',
|
|
22
|
+
'CRITICAL': 'CRIT',
|
|
23
|
+
'DEBUG': 'DEBG'
|
|
24
|
+
}
|
|
25
|
+
record.levelname = level_mapping.get(record.levelname, record.levelname)
|
|
26
|
+
return super().format(record)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class LoggingSetup:
|
|
30
|
+
"""Centralized logging configuration manager."""
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
self._configured = False
|
|
34
|
+
self._current_config = {}
|
|
35
|
+
|
|
36
|
+
def setup_bootstrap_logging(self, log_dir: Optional[Path] = None):
|
|
37
|
+
"""Setup minimal logging before config system is available.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
log_dir: Optional log directory, defaults to .kollabor-cli/logs
|
|
41
|
+
"""
|
|
42
|
+
if log_dir is None:
|
|
43
|
+
from ..utils.config_utils import get_config_directory
|
|
44
|
+
config_dir = get_config_directory()
|
|
45
|
+
log_dir = config_dir / "logs"
|
|
46
|
+
|
|
47
|
+
# Ensure log directory exists
|
|
48
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
49
|
+
|
|
50
|
+
# Setup with hardcoded defaults that match current behavior
|
|
51
|
+
log_file = log_dir / "kollabor.log"
|
|
52
|
+
|
|
53
|
+
handler = logging.handlers.TimedRotatingFileHandler(
|
|
54
|
+
filename=str(log_file),
|
|
55
|
+
when='D', # Daily rotation
|
|
56
|
+
interval=1,
|
|
57
|
+
backupCount=1,
|
|
58
|
+
encoding='utf-8'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Add thread safety
|
|
62
|
+
handler.lock = threading.RLock()
|
|
63
|
+
|
|
64
|
+
# Use compact formatter
|
|
65
|
+
formatter = CompactFormatter(
|
|
66
|
+
"%(asctime)s - %(levelname)-4s - %(message)-100s - %(filename)s:%(lineno)04d"
|
|
67
|
+
)
|
|
68
|
+
handler.setFormatter(formatter)
|
|
69
|
+
|
|
70
|
+
# Configure logging
|
|
71
|
+
logging.basicConfig(
|
|
72
|
+
level=logging.INFO,
|
|
73
|
+
handlers=[
|
|
74
|
+
handler,
|
|
75
|
+
logging.NullHandler() # Suppress console output
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
self._configured = True
|
|
80
|
+
self._current_config = {
|
|
81
|
+
'level': 'INFO',
|
|
82
|
+
'file': str(log_file),
|
|
83
|
+
'format': 'compact'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Apply formatter to all existing handlers
|
|
87
|
+
self._apply_formatter_to_all_loggers(formatter)
|
|
88
|
+
|
|
89
|
+
def setup_from_config(self, config: Dict[str, Any]):
|
|
90
|
+
"""Setup logging from configuration system.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
config: Configuration dictionary with logging settings
|
|
94
|
+
"""
|
|
95
|
+
logging_config = config.get('logging', {})
|
|
96
|
+
|
|
97
|
+
# Extract configuration values
|
|
98
|
+
level = logging_config.get('level', 'INFO').upper()
|
|
99
|
+
log_file = logging_config.get('file', '.kollabor-cli/logs/kollabor.log')
|
|
100
|
+
format_type = logging_config.get('format_type', 'compact')
|
|
101
|
+
custom_format = logging_config.get('format', None)
|
|
102
|
+
|
|
103
|
+
# Convert string level to logging constant
|
|
104
|
+
numeric_level = getattr(logging, level, logging.INFO)
|
|
105
|
+
|
|
106
|
+
# Ensure log directory exists
|
|
107
|
+
log_path = Path(log_file)
|
|
108
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
109
|
+
|
|
110
|
+
# Create new handler
|
|
111
|
+
handler = logging.handlers.TimedRotatingFileHandler(
|
|
112
|
+
filename=str(log_path),
|
|
113
|
+
when='D',
|
|
114
|
+
interval=1,
|
|
115
|
+
backupCount=1,
|
|
116
|
+
encoding='utf-8'
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Add thread safety
|
|
120
|
+
handler.lock = threading.RLock()
|
|
121
|
+
|
|
122
|
+
# Choose formatter based on config
|
|
123
|
+
if format_type == 'compact':
|
|
124
|
+
formatter = CompactFormatter(
|
|
125
|
+
"%(asctime)s - %(levelname)-4s - %(message)-100s - %(filename)s:%(lineno)04d"
|
|
126
|
+
)
|
|
127
|
+
elif custom_format:
|
|
128
|
+
formatter = logging.Formatter(custom_format)
|
|
129
|
+
else:
|
|
130
|
+
# Standard format
|
|
131
|
+
formatter = logging.Formatter(
|
|
132
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
handler.setFormatter(formatter)
|
|
136
|
+
|
|
137
|
+
# Clear existing handlers and setup new one
|
|
138
|
+
root_logger = logging.getLogger()
|
|
139
|
+
for old_handler in root_logger.handlers[:]:
|
|
140
|
+
root_logger.removeHandler(old_handler)
|
|
141
|
+
|
|
142
|
+
logging.basicConfig(
|
|
143
|
+
level=numeric_level,
|
|
144
|
+
handlers=[
|
|
145
|
+
handler,
|
|
146
|
+
logging.NullHandler()
|
|
147
|
+
],
|
|
148
|
+
force=True # Force reconfiguration
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
self._configured = True
|
|
152
|
+
self._current_config = {
|
|
153
|
+
'level': level,
|
|
154
|
+
'file': str(log_path),
|
|
155
|
+
'format': format_type,
|
|
156
|
+
'custom_format': custom_format
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Apply formatter to all existing loggers
|
|
160
|
+
self._apply_formatter_to_all_loggers(formatter)
|
|
161
|
+
|
|
162
|
+
logging.getLogger(__name__).info(
|
|
163
|
+
f"Logging reconfigured - Level: {level}, File: {log_file}, Format: {format_type}"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def _apply_formatter_to_all_loggers(self, formatter):
|
|
167
|
+
"""Apply formatter to all existing loggers and handlers."""
|
|
168
|
+
# Apply to root logger handlers
|
|
169
|
+
for root_handler in logging.getLogger().handlers:
|
|
170
|
+
root_handler.setFormatter(formatter)
|
|
171
|
+
|
|
172
|
+
# Apply to all existing logger handlers
|
|
173
|
+
for logger_name in logging.Logger.manager.loggerDict:
|
|
174
|
+
existing_logger = logging.getLogger(logger_name)
|
|
175
|
+
for existing_handler in existing_logger.handlers:
|
|
176
|
+
existing_handler.setFormatter(formatter)
|
|
177
|
+
|
|
178
|
+
def get_current_config(self) -> Dict[str, Any]:
|
|
179
|
+
"""Get current logging configuration."""
|
|
180
|
+
return self._current_config.copy()
|
|
181
|
+
|
|
182
|
+
def is_configured(self) -> bool:
|
|
183
|
+
"""Check if logging has been configured."""
|
|
184
|
+
return self._configured
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# Global instance
|
|
188
|
+
logging_setup = LoggingSetup()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def setup_bootstrap_logging(log_dir: Optional[Path] = None):
|
|
192
|
+
"""Setup bootstrap logging before config system is available."""
|
|
193
|
+
logging_setup.setup_bootstrap_logging(log_dir)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def setup_from_config(config: Dict[str, Any]):
|
|
197
|
+
"""Setup logging from configuration system."""
|
|
198
|
+
logging_setup.setup_from_config(config)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def get_current_config() -> Dict[str, Any]:
|
|
202
|
+
"""Get current logging configuration."""
|
|
203
|
+
return logging_setup.get_current_config()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def is_configured() -> bool:
|
|
207
|
+
"""Check if logging has been configured."""
|
|
208
|
+
return logging_setup.is_configured()
|
core/models/__init__.py
ADDED
core/models/base.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Shared data models for Kollabor CLI."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ConversationMessage:
|
|
10
|
+
"""A single message in the conversation.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
role: Role of the message sender (user, assistant, system, tool).
|
|
14
|
+
content: The message content.
|
|
15
|
+
timestamp: When the message was created.
|
|
16
|
+
metadata: Additional metadata.
|
|
17
|
+
thinking: Optional thinking process information.
|
|
18
|
+
"""
|
|
19
|
+
role: str
|
|
20
|
+
content: str
|
|
21
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
22
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
23
|
+
thinking: Optional[str] = None
|
core/plugins/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Plugin subsystem for Kollabor CLI."""
|
|
2
|
+
|
|
3
|
+
from .registry import PluginRegistry
|
|
4
|
+
from .discovery import PluginDiscovery
|
|
5
|
+
from .factory import PluginFactory
|
|
6
|
+
from .collector import PluginStatusCollector
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'PluginRegistry',
|
|
10
|
+
'PluginDiscovery',
|
|
11
|
+
'PluginFactory',
|
|
12
|
+
'PluginStatusCollector'
|
|
13
|
+
]
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Plugin status collector for aggregating status information from plugins."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict, List
|
|
5
|
+
|
|
6
|
+
from ..utils.plugin_utils import collect_plugin_status_safely
|
|
7
|
+
from ..utils.error_utils import safe_execute
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PluginStatusCollector:
|
|
13
|
+
"""Collects and aggregates status information from plugin instances.
|
|
14
|
+
|
|
15
|
+
This class is responsible for gathering status lines from all plugins,
|
|
16
|
+
organizing them by display areas, and providing aggregated status data.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
"""Initialize the plugin status collector."""
|
|
21
|
+
self.last_status_collection: Dict[str, Dict[str, List[str]]] = {}
|
|
22
|
+
self.collection_errors: Dict[str, str] = {}
|
|
23
|
+
logger.info("PluginStatusCollector initialized")
|
|
24
|
+
|
|
25
|
+
def collect_plugin_status(self, plugin_name: str, plugin_instance: Any) -> Dict[str, List[str]]:
|
|
26
|
+
"""Collect status information from a single plugin.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
plugin_name: Name of the plugin.
|
|
30
|
+
plugin_instance: The plugin instance to collect status from.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dictionary with areas A, B, C containing lists of status lines.
|
|
34
|
+
"""
|
|
35
|
+
plugin_status = collect_plugin_status_safely(plugin_instance, plugin_name)
|
|
36
|
+
|
|
37
|
+
# Store the status for this plugin
|
|
38
|
+
self.last_status_collection[plugin_name] = plugin_status
|
|
39
|
+
|
|
40
|
+
# Clear any previous collection errors for this plugin
|
|
41
|
+
if plugin_name in self.collection_errors:
|
|
42
|
+
del self.collection_errors[plugin_name]
|
|
43
|
+
|
|
44
|
+
return plugin_status
|
|
45
|
+
|
|
46
|
+
def collect_all_status(self, plugin_instances: Dict[str, Any]) -> Dict[str, List[str]]:
|
|
47
|
+
"""Collect status lines from all plugins organized by area.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
plugin_instances: Dictionary of plugin instances.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dictionary with areas A, B, C containing aggregated status lines.
|
|
54
|
+
"""
|
|
55
|
+
status_areas = {"A": [], "B": [], "C": []}
|
|
56
|
+
|
|
57
|
+
for plugin_name, plugin_instance in plugin_instances.items():
|
|
58
|
+
plugin_status = self.collect_plugin_status(plugin_name, plugin_instance)
|
|
59
|
+
|
|
60
|
+
# Merge the status from this plugin into our aggregated status
|
|
61
|
+
for area in ["A", "B", "C"]:
|
|
62
|
+
if area in plugin_status:
|
|
63
|
+
status_areas[area].extend(plugin_status[area])
|
|
64
|
+
|
|
65
|
+
#logger.debug(f"Collected status from {len(plugin_instances)} plugins")
|
|
66
|
+
return status_areas
|
|
67
|
+
|
|
68
|
+
def get_plugin_startup_info(self, plugin_name: str, plugin_class: type, config: Any) -> List[str]:
|
|
69
|
+
"""Get startup information for a specific plugin.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
plugin_name: Name of the plugin.
|
|
73
|
+
plugin_class: The plugin class.
|
|
74
|
+
config: Configuration manager instance.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
List of startup info strings, or empty list if no info available.
|
|
78
|
+
"""
|
|
79
|
+
def get_startup_info():
|
|
80
|
+
return plugin_class.get_startup_info(config)
|
|
81
|
+
|
|
82
|
+
result = safe_execute(
|
|
83
|
+
get_startup_info,
|
|
84
|
+
f"getting startup info from plugin {plugin_name}",
|
|
85
|
+
default=[],
|
|
86
|
+
logger_instance=logger
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return result if isinstance(result, list) else []
|
|
90
|
+
|
|
91
|
+
def collect_all_startup_info(self, plugin_classes: Dict[str, type], config: Any) -> Dict[str, List[str]]:
|
|
92
|
+
"""Collect startup information from all plugin classes.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
plugin_classes: Dictionary mapping plugin names to classes.
|
|
96
|
+
config: Configuration manager instance.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Dictionary mapping plugin names to their startup info lists.
|
|
100
|
+
"""
|
|
101
|
+
startup_info = {}
|
|
102
|
+
|
|
103
|
+
for plugin_name, plugin_class in plugin_classes.items():
|
|
104
|
+
info_list = self.get_plugin_startup_info(plugin_name, plugin_class, config)
|
|
105
|
+
if info_list:
|
|
106
|
+
startup_info[plugin_name] = info_list
|
|
107
|
+
|
|
108
|
+
logger.debug(f"Collected startup info from {len(startup_info)} plugins")
|
|
109
|
+
return startup_info
|
|
110
|
+
|
|
111
|
+
def get_status_summary(self) -> Dict[str, Any]:
|
|
112
|
+
"""Get a summary of the last status collection.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dictionary with status collection summary.
|
|
116
|
+
"""
|
|
117
|
+
total_lines = 0
|
|
118
|
+
areas_summary = {"A": 0, "B": 0, "C": 0}
|
|
119
|
+
|
|
120
|
+
for plugin_name, status in self.last_status_collection.items():
|
|
121
|
+
for area in ["A", "B", "C"]:
|
|
122
|
+
if area in status:
|
|
123
|
+
line_count = len(status[area])
|
|
124
|
+
areas_summary[area] += line_count
|
|
125
|
+
total_lines += line_count
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
"total_plugins": len(self.last_status_collection),
|
|
129
|
+
"total_status_lines": total_lines,
|
|
130
|
+
"lines_per_area": areas_summary,
|
|
131
|
+
"collection_errors": len(self.collection_errors),
|
|
132
|
+
"plugins_with_status": [
|
|
133
|
+
name for name, status in self.last_status_collection.items()
|
|
134
|
+
if any(status.get(area) for area in ["A", "B", "C"])
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
def get_plugin_status_details(self, plugin_name: str) -> Dict[str, Any]:
|
|
139
|
+
"""Get detailed status information for a specific plugin.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
plugin_name: Name of the plugin.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Dictionary with detailed status information for the plugin.
|
|
146
|
+
"""
|
|
147
|
+
if plugin_name not in self.last_status_collection:
|
|
148
|
+
return {
|
|
149
|
+
"plugin_name": plugin_name,
|
|
150
|
+
"status_collected": False,
|
|
151
|
+
"error": "No status collection found"
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
status = self.last_status_collection[plugin_name]
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
"plugin_name": plugin_name,
|
|
158
|
+
"status_collected": True,
|
|
159
|
+
"areas": {
|
|
160
|
+
area: {
|
|
161
|
+
"line_count": len(lines),
|
|
162
|
+
"lines": lines
|
|
163
|
+
}
|
|
164
|
+
for area, lines in status.items()
|
|
165
|
+
},
|
|
166
|
+
"has_error": plugin_name in self.collection_errors,
|
|
167
|
+
"error": self.collection_errors.get(plugin_name)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
def clear_status_history(self) -> None:
|
|
171
|
+
"""Clear all stored status collection history."""
|
|
172
|
+
self.last_status_collection.clear()
|
|
173
|
+
self.collection_errors.clear()
|
|
174
|
+
logger.debug("Cleared status collection history")
|
|
175
|
+
|
|
176
|
+
def get_status_by_area(self, area: str) -> List[str]:
|
|
177
|
+
"""Get all status lines for a specific area across all plugins.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
area: The area to get status for ("A", "B", or "C").
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
List of status lines for the specified area.
|
|
184
|
+
"""
|
|
185
|
+
if area not in ["A", "B", "C"]:
|
|
186
|
+
logger.warning(f"Invalid status area: {area}")
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
lines = []
|
|
190
|
+
for plugin_name, status in self.last_status_collection.items():
|
|
191
|
+
if area in status:
|
|
192
|
+
lines.extend(status[area])
|
|
193
|
+
|
|
194
|
+
return lines
|
|
195
|
+
|
|
196
|
+
def get_collector_stats(self) -> Dict[str, Any]:
|
|
197
|
+
"""Get statistics about the collector's operations.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Dictionary with collector statistics.
|
|
201
|
+
"""
|
|
202
|
+
total_collections = len(self.last_status_collection)
|
|
203
|
+
successful_collections = total_collections - len(self.collection_errors)
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"total_collections": total_collections,
|
|
207
|
+
"successful_collections": successful_collections,
|
|
208
|
+
"collection_errors": len(self.collection_errors),
|
|
209
|
+
"plugins_tracked": list(self.last_status_collection.keys()),
|
|
210
|
+
"error_plugins": list(self.collection_errors.keys()),
|
|
211
|
+
"status_summary": self.get_status_summary()
|
|
212
|
+
}
|