kollabor 0.4.9__py3-none-any.whl → 0.4.15__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.
- agents/__init__.py +2 -0
- agents/coder/__init__.py +0 -0
- agents/coder/agent.json +4 -0
- agents/coder/api-integration.md +2150 -0
- agents/coder/cli-pretty.md +765 -0
- agents/coder/code-review.md +1092 -0
- agents/coder/database-design.md +1525 -0
- agents/coder/debugging.md +1102 -0
- agents/coder/dependency-management.md +1397 -0
- agents/coder/git-workflow.md +1099 -0
- agents/coder/refactoring.md +1454 -0
- agents/coder/security-hardening.md +1732 -0
- agents/coder/system_prompt.md +1448 -0
- agents/coder/tdd.md +1367 -0
- agents/creative-writer/__init__.py +0 -0
- agents/creative-writer/agent.json +4 -0
- agents/creative-writer/character-development.md +1852 -0
- agents/creative-writer/dialogue-craft.md +1122 -0
- agents/creative-writer/plot-structure.md +1073 -0
- agents/creative-writer/revision-editing.md +1484 -0
- agents/creative-writer/system_prompt.md +690 -0
- agents/creative-writer/worldbuilding.md +2049 -0
- agents/data-analyst/__init__.py +30 -0
- agents/data-analyst/agent.json +4 -0
- agents/data-analyst/data-visualization.md +992 -0
- agents/data-analyst/exploratory-data-analysis.md +1110 -0
- agents/data-analyst/pandas-data-manipulation.md +1081 -0
- agents/data-analyst/sql-query-optimization.md +881 -0
- agents/data-analyst/statistical-analysis.md +1118 -0
- agents/data-analyst/system_prompt.md +928 -0
- agents/default/__init__.py +0 -0
- agents/default/agent.json +4 -0
- agents/default/dead-code.md +794 -0
- agents/default/explore-agent-system.md +585 -0
- agents/default/system_prompt.md +1448 -0
- agents/kollabor/__init__.py +0 -0
- agents/kollabor/analyze-plugin-lifecycle.md +175 -0
- agents/kollabor/analyze-terminal-rendering.md +388 -0
- agents/kollabor/code-review.md +1092 -0
- agents/kollabor/debug-mcp-integration.md +521 -0
- agents/kollabor/debug-plugin-hooks.md +547 -0
- agents/kollabor/debugging.md +1102 -0
- agents/kollabor/dependency-management.md +1397 -0
- agents/kollabor/git-workflow.md +1099 -0
- agents/kollabor/inspect-llm-conversation.md +148 -0
- agents/kollabor/monitor-event-bus.md +558 -0
- agents/kollabor/profile-performance.md +576 -0
- agents/kollabor/refactoring.md +1454 -0
- agents/kollabor/system_prompt copy.md +1448 -0
- agents/kollabor/system_prompt.md +757 -0
- agents/kollabor/trace-command-execution.md +178 -0
- agents/kollabor/validate-config.md +879 -0
- agents/research/__init__.py +0 -0
- agents/research/agent.json +4 -0
- agents/research/architecture-mapping.md +1099 -0
- agents/research/codebase-analysis.md +1077 -0
- agents/research/dependency-audit.md +1027 -0
- agents/research/performance-profiling.md +1047 -0
- agents/research/security-review.md +1359 -0
- agents/research/system_prompt.md +492 -0
- agents/technical-writer/__init__.py +0 -0
- agents/technical-writer/agent.json +4 -0
- agents/technical-writer/api-documentation.md +2328 -0
- agents/technical-writer/changelog-management.md +1181 -0
- agents/technical-writer/readme-writing.md +1360 -0
- agents/technical-writer/style-guide.md +1410 -0
- agents/technical-writer/system_prompt.md +653 -0
- agents/technical-writer/tutorial-creation.md +1448 -0
- core/__init__.py +0 -2
- core/application.py +343 -88
- core/cli.py +229 -10
- core/commands/menu_renderer.py +463 -59
- core/commands/registry.py +14 -9
- core/commands/system_commands.py +2461 -14
- core/config/loader.py +151 -37
- core/config/service.py +18 -6
- core/events/bus.py +29 -9
- core/events/executor.py +205 -75
- core/events/models.py +27 -8
- core/fullscreen/command_integration.py +20 -24
- core/fullscreen/components/__init__.py +10 -1
- core/fullscreen/components/matrix_components.py +1 -2
- core/fullscreen/components/space_shooter_components.py +654 -0
- core/fullscreen/plugin.py +5 -0
- core/fullscreen/renderer.py +52 -13
- core/fullscreen/session.py +52 -15
- core/io/__init__.py +29 -5
- core/io/buffer_manager.py +6 -1
- core/io/config_status_view.py +7 -29
- core/io/core_status_views.py +267 -347
- core/io/input/__init__.py +25 -0
- core/io/input/command_mode_handler.py +711 -0
- core/io/input/display_controller.py +128 -0
- core/io/input/hook_registrar.py +286 -0
- core/io/input/input_loop_manager.py +421 -0
- core/io/input/key_press_handler.py +502 -0
- core/io/input/modal_controller.py +1011 -0
- core/io/input/paste_processor.py +339 -0
- core/io/input/status_modal_renderer.py +184 -0
- core/io/input_errors.py +5 -1
- core/io/input_handler.py +211 -2452
- core/io/key_parser.py +7 -0
- core/io/layout.py +15 -3
- core/io/message_coordinator.py +111 -2
- core/io/message_renderer.py +129 -4
- core/io/status_renderer.py +147 -607
- core/io/terminal_renderer.py +97 -51
- core/io/terminal_state.py +21 -4
- core/io/visual_effects.py +816 -165
- core/llm/agent_manager.py +1063 -0
- core/llm/api_adapters/__init__.py +44 -0
- core/llm/api_adapters/anthropic_adapter.py +432 -0
- core/llm/api_adapters/base.py +241 -0
- core/llm/api_adapters/openai_adapter.py +326 -0
- core/llm/api_communication_service.py +167 -113
- core/llm/conversation_logger.py +322 -16
- core/llm/conversation_manager.py +556 -30
- core/llm/file_operations_executor.py +84 -32
- core/llm/llm_service.py +934 -103
- core/llm/mcp_integration.py +541 -57
- core/llm/message_display_service.py +135 -18
- core/llm/plugin_sdk.py +1 -2
- core/llm/profile_manager.py +1183 -0
- core/llm/response_parser.py +274 -56
- core/llm/response_processor.py +16 -3
- core/llm/tool_executor.py +6 -1
- core/logging/__init__.py +2 -0
- core/logging/setup.py +34 -6
- core/models/resume.py +54 -0
- core/plugins/__init__.py +4 -2
- core/plugins/base.py +127 -0
- core/plugins/collector.py +23 -161
- core/plugins/discovery.py +37 -3
- core/plugins/factory.py +6 -12
- core/plugins/registry.py +5 -17
- core/ui/config_widgets.py +128 -28
- core/ui/live_modal_renderer.py +2 -1
- core/ui/modal_actions.py +5 -0
- core/ui/modal_overlay_renderer.py +0 -60
- core/ui/modal_renderer.py +268 -7
- core/ui/modal_state_manager.py +29 -4
- core/ui/widgets/base_widget.py +7 -0
- core/updates/__init__.py +10 -0
- core/updates/version_check_service.py +348 -0
- core/updates/version_comparator.py +103 -0
- core/utils/config_utils.py +685 -526
- core/utils/plugin_utils.py +1 -1
- core/utils/session_naming.py +111 -0
- fonts/LICENSE +21 -0
- fonts/README.md +46 -0
- fonts/SymbolsNerdFont-Regular.ttf +0 -0
- fonts/SymbolsNerdFontMono-Regular.ttf +0 -0
- fonts/__init__.py +44 -0
- {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/METADATA +54 -4
- kollabor-0.4.15.dist-info/RECORD +228 -0
- {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/top_level.txt +2 -0
- plugins/agent_orchestrator/__init__.py +39 -0
- plugins/agent_orchestrator/activity_monitor.py +181 -0
- plugins/agent_orchestrator/file_attacher.py +77 -0
- plugins/agent_orchestrator/message_injector.py +135 -0
- plugins/agent_orchestrator/models.py +48 -0
- plugins/agent_orchestrator/orchestrator.py +403 -0
- plugins/agent_orchestrator/plugin.py +976 -0
- plugins/agent_orchestrator/xml_parser.py +191 -0
- plugins/agent_orchestrator_plugin.py +9 -0
- plugins/enhanced_input/box_styles.py +1 -0
- plugins/enhanced_input/color_engine.py +19 -4
- plugins/enhanced_input/config.py +2 -2
- plugins/enhanced_input_plugin.py +61 -11
- plugins/fullscreen/__init__.py +6 -2
- plugins/fullscreen/example_plugin.py +1035 -222
- plugins/fullscreen/setup_wizard_plugin.py +592 -0
- plugins/fullscreen/space_shooter_plugin.py +131 -0
- plugins/hook_monitoring_plugin.py +436 -78
- plugins/query_enhancer_plugin.py +66 -30
- plugins/resume_conversation_plugin.py +1494 -0
- plugins/save_conversation_plugin.py +98 -32
- plugins/system_commands_plugin.py +70 -56
- plugins/tmux_plugin.py +154 -78
- plugins/workflow_enforcement_plugin.py +94 -92
- system_prompt/default.md +952 -886
- core/io/input_mode_manager.py +0 -402
- core/io/modal_interaction_handler.py +0 -315
- core/io/raw_input_processor.py +0 -946
- core/storage/__init__.py +0 -5
- core/storage/state_manager.py +0 -84
- core/ui/widget_integration.py +0 -222
- core/utils/key_reader.py +0 -171
- kollabor-0.4.9.dist-info/RECORD +0 -128
- {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/WHEEL +0 -0
- {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/entry_points.txt +0 -0
- {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/licenses/LICENSE +0 -0
core/models/resume.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Data models for resume functionality."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class SessionMetadata:
|
|
10
|
+
"""Metadata for a conversation session."""
|
|
11
|
+
session_id: str
|
|
12
|
+
start_time: Optional[datetime]
|
|
13
|
+
end_time: Optional[datetime]
|
|
14
|
+
message_count: int
|
|
15
|
+
turn_count: int
|
|
16
|
+
working_directory: str
|
|
17
|
+
git_branch: str
|
|
18
|
+
themes: List[str]
|
|
19
|
+
files_mentioned: List[str]
|
|
20
|
+
last_activity: Optional[datetime]
|
|
21
|
+
size_bytes: int
|
|
22
|
+
is_valid: bool
|
|
23
|
+
validation_issues: List[str]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class SessionSummary:
|
|
28
|
+
"""Summary of a conversation session."""
|
|
29
|
+
metadata: SessionMetadata
|
|
30
|
+
preview_messages: List[Dict]
|
|
31
|
+
key_topics: List[str]
|
|
32
|
+
user_patterns: List[str]
|
|
33
|
+
project_context: Dict[str, Any]
|
|
34
|
+
compatibility_score: float
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class ConversationMetadata:
|
|
39
|
+
"""Metadata for conversation discovery."""
|
|
40
|
+
file_path: str
|
|
41
|
+
session_id: str
|
|
42
|
+
title: str
|
|
43
|
+
message_count: int
|
|
44
|
+
created_time: Optional[datetime]
|
|
45
|
+
modified_time: Optional[datetime]
|
|
46
|
+
last_message_preview: str
|
|
47
|
+
topics: List[str]
|
|
48
|
+
file_id: str # Short ID for display (#12345)
|
|
49
|
+
working_directory: str
|
|
50
|
+
git_branch: str
|
|
51
|
+
duration: Optional[str]
|
|
52
|
+
size_bytes: int
|
|
53
|
+
preview_messages: List[Dict]
|
|
54
|
+
search_relevance: Optional[float] = None
|
core/plugins/__init__.py
CHANGED
|
@@ -4,10 +4,12 @@ from .registry import PluginRegistry
|
|
|
4
4
|
from .discovery import PluginDiscovery
|
|
5
5
|
from .factory import PluginFactory
|
|
6
6
|
from .collector import PluginStatusCollector
|
|
7
|
+
from .base import BasePlugin
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
'PluginRegistry',
|
|
10
|
-
'PluginDiscovery',
|
|
11
|
+
'PluginDiscovery',
|
|
11
12
|
'PluginFactory',
|
|
12
|
-
'PluginStatusCollector'
|
|
13
|
+
'PluginStatusCollector',
|
|
14
|
+
'BasePlugin'
|
|
13
15
|
]
|
core/plugins/base.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Base plugin class for Kollabor CLI plugins.
|
|
2
|
+
|
|
3
|
+
This module defines the BasePlugin class that all plugins can inherit from.
|
|
4
|
+
It provides default implementations for plugin lifecycle methods including
|
|
5
|
+
CLI argument registration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BasePlugin:
|
|
13
|
+
"""Base class for all Kollabor CLI plugins.
|
|
14
|
+
|
|
15
|
+
Plugins can inherit from this class to get default implementations
|
|
16
|
+
of common plugin methods. The class provides static methods for
|
|
17
|
+
CLI argument registration and early argument handling.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def register_cli_args(parser: argparse.ArgumentParser) -> None:
|
|
22
|
+
"""Register custom CLI arguments.
|
|
23
|
+
|
|
24
|
+
Called during early plugin discovery, before app initialization.
|
|
25
|
+
Use parser.add_argument_group() to organize args by plugin.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
parser: The ArgumentParser instance to add arguments to.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
@staticmethod
|
|
32
|
+
def register_cli_args(parser):
|
|
33
|
+
group = parser.add_argument_group("My Plugin")
|
|
34
|
+
group.add_argument("--my-arg", type=str,
|
|
35
|
+
help="My custom argument")
|
|
36
|
+
"""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def handle_early_args(args: argparse.Namespace) -> bool:
|
|
41
|
+
"""Handle args that should exit before app starts.
|
|
42
|
+
|
|
43
|
+
Called after argument parsing but before app initialization.
|
|
44
|
+
Return True to exit immediately (e.g., --capture mode).
|
|
45
|
+
Return False to continue normal startup.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
args: The parsed CLI arguments namespace.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
True to exit immediately, False to continue normal startup.
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
@staticmethod
|
|
55
|
+
def handle_early_args(args):
|
|
56
|
+
if hasattr(args, 'my_flag') and args.my_flag:
|
|
57
|
+
print("Early exit triggered")
|
|
58
|
+
return True
|
|
59
|
+
return False
|
|
60
|
+
"""
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
def initialize(self, args: argparse.Namespace = None, **kwargs) -> None:
|
|
64
|
+
"""Initialize the plugin.
|
|
65
|
+
|
|
66
|
+
Called during app startup. The args parameter contains
|
|
67
|
+
parsed CLI arguments including any plugin-registered args.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
args: Parsed CLI arguments (optional, None if not available).
|
|
71
|
+
**kwargs: Additional initialization parameters including:
|
|
72
|
+
- event_bus: Event bus for hook registration
|
|
73
|
+
- config: Configuration manager
|
|
74
|
+
- command_registry: Command registry for slash commands
|
|
75
|
+
- input_handler: Input handler instance
|
|
76
|
+
- renderer: Terminal renderer
|
|
77
|
+
- llm_service: LLM service instance
|
|
78
|
+
- conversation_logger: Conversation logger instance
|
|
79
|
+
- conversation_manager: Conversation manager instance
|
|
80
|
+
"""
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def register_hooks(self) -> None:
|
|
84
|
+
"""Register plugin hooks with the event bus.
|
|
85
|
+
|
|
86
|
+
Called during plugin initialization after initialize().
|
|
87
|
+
Override this method to register event hooks.
|
|
88
|
+
"""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
def shutdown(self) -> None:
|
|
92
|
+
"""Shutdown the plugin.
|
|
93
|
+
|
|
94
|
+
Called during app shutdown. Override this method to
|
|
95
|
+
perform cleanup tasks.
|
|
96
|
+
"""
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def get_default_config() -> dict[str, Any]:
|
|
101
|
+
"""Get default configuration for this plugin.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Dictionary with default configuration values.
|
|
105
|
+
"""
|
|
106
|
+
return {}
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def get_startup_info(config) -> list[str]:
|
|
110
|
+
"""Get startup information for this plugin.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
config: Configuration manager instance.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
List of strings to display during startup.
|
|
117
|
+
"""
|
|
118
|
+
return []
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def get_config_widgets() -> dict[str, Any]:
|
|
122
|
+
"""Get configuration widgets for this plugin.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Widget section definition for the config modal.
|
|
126
|
+
"""
|
|
127
|
+
return {}
|
core/plugins/collector.py
CHANGED
|
@@ -1,212 +1,74 @@
|
|
|
1
|
-
"""Plugin
|
|
1
|
+
"""Plugin collector for gathering plugin information."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, Dict, List
|
|
5
5
|
|
|
6
|
-
from ..utils.plugin_utils import collect_plugin_status_safely
|
|
7
6
|
from ..utils.error_utils import safe_execute
|
|
8
7
|
|
|
9
8
|
logger = logging.getLogger(__name__)
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class PluginStatusCollector:
|
|
13
|
-
"""Collects
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
"""Collects plugin information like startup info.
|
|
13
|
+
|
|
14
|
+
Note: Status line collection has been removed in favor of
|
|
15
|
+
content provider-based status views.
|
|
17
16
|
"""
|
|
18
|
-
|
|
17
|
+
|
|
19
18
|
def __init__(self):
|
|
20
|
-
"""Initialize the plugin
|
|
21
|
-
self.last_status_collection: Dict[str, Dict[str, List[str]]] = {}
|
|
22
|
-
self.collection_errors: Dict[str, str] = {}
|
|
19
|
+
"""Initialize the plugin collector."""
|
|
23
20
|
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
|
-
|
|
21
|
+
|
|
68
22
|
def get_plugin_startup_info(self, plugin_name: str, plugin_class: type, config: Any) -> List[str]:
|
|
69
23
|
"""Get startup information for a specific plugin.
|
|
70
|
-
|
|
24
|
+
|
|
71
25
|
Args:
|
|
72
26
|
plugin_name: Name of the plugin.
|
|
73
27
|
plugin_class: The plugin class.
|
|
74
28
|
config: Configuration manager instance.
|
|
75
|
-
|
|
29
|
+
|
|
76
30
|
Returns:
|
|
77
31
|
List of startup info strings, or empty list if no info available.
|
|
78
32
|
"""
|
|
79
33
|
def get_startup_info():
|
|
80
34
|
return plugin_class.get_startup_info(config)
|
|
81
|
-
|
|
35
|
+
|
|
82
36
|
result = safe_execute(
|
|
83
37
|
get_startup_info,
|
|
84
38
|
f"getting startup info from plugin {plugin_name}",
|
|
85
39
|
default=[],
|
|
86
40
|
logger_instance=logger
|
|
87
41
|
)
|
|
88
|
-
|
|
42
|
+
|
|
89
43
|
return result if isinstance(result, list) else []
|
|
90
|
-
|
|
44
|
+
|
|
91
45
|
def collect_all_startup_info(self, plugin_classes: Dict[str, type], config: Any) -> Dict[str, List[str]]:
|
|
92
46
|
"""Collect startup information from all plugin classes.
|
|
93
|
-
|
|
47
|
+
|
|
94
48
|
Args:
|
|
95
49
|
plugin_classes: Dictionary mapping plugin names to classes.
|
|
96
50
|
config: Configuration manager instance.
|
|
97
|
-
|
|
51
|
+
|
|
98
52
|
Returns:
|
|
99
53
|
Dictionary mapping plugin names to their startup info lists.
|
|
100
54
|
"""
|
|
101
55
|
startup_info = {}
|
|
102
|
-
|
|
56
|
+
|
|
103
57
|
for plugin_name, plugin_class in plugin_classes.items():
|
|
104
58
|
info_list = self.get_plugin_startup_info(plugin_name, plugin_class, config)
|
|
105
59
|
if info_list:
|
|
106
60
|
startup_info[plugin_name] = info_list
|
|
107
|
-
|
|
61
|
+
|
|
108
62
|
logger.debug(f"Collected startup info from {len(startup_info)} plugins")
|
|
109
63
|
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
|
-
|
|
64
|
+
|
|
196
65
|
def get_collector_stats(self) -> Dict[str, Any]:
|
|
197
|
-
"""Get statistics about the collector
|
|
198
|
-
|
|
66
|
+
"""Get statistics about the collector.
|
|
67
|
+
|
|
199
68
|
Returns:
|
|
200
69
|
Dictionary with collector statistics.
|
|
201
70
|
"""
|
|
202
|
-
total_collections = len(self.last_status_collection)
|
|
203
|
-
successful_collections = total_collections - len(self.collection_errors)
|
|
204
|
-
|
|
205
71
|
return {
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
|
|
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
|
-
}
|
|
72
|
+
"type": "startup_info_collector",
|
|
73
|
+
"description": "Collects plugin startup information"
|
|
74
|
+
}
|
core/plugins/discovery.py
CHANGED
|
@@ -275,18 +275,52 @@ class PluginDiscovery:
|
|
|
275
275
|
|
|
276
276
|
def discover_and_load(self) -> Dict[str, Type]:
|
|
277
277
|
"""Perform complete discovery and loading process.
|
|
278
|
-
|
|
278
|
+
|
|
279
279
|
Returns:
|
|
280
280
|
Dictionary mapping plugin names to their classes.
|
|
281
281
|
"""
|
|
282
282
|
# Scan for plugin files
|
|
283
283
|
self.scan_plugin_files()
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
# Load all discovered modules
|
|
286
286
|
self.load_all_modules()
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
logger.info(f"Discovery complete: {len(self.loaded_classes)} plugins loaded")
|
|
289
289
|
return self.loaded_classes
|
|
290
|
+
|
|
291
|
+
def discover_classes_only(self) -> List[Type]:
|
|
292
|
+
"""Lightweight discovery that only loads plugin classes.
|
|
293
|
+
|
|
294
|
+
Does NOT instantiate plugins. Used for CLI arg registration
|
|
295
|
+
before app initialization. This allows plugins to register
|
|
296
|
+
custom CLI arguments without full plugin initialization.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
List of plugin class types.
|
|
300
|
+
|
|
301
|
+
Note:
|
|
302
|
+
This is a minimal discovery that loads modules and extracts
|
|
303
|
+
plugin classes but does not perform full instantiation or
|
|
304
|
+
configuration merging.
|
|
305
|
+
"""
|
|
306
|
+
# Scan for plugin files
|
|
307
|
+
self.scan_plugin_files()
|
|
308
|
+
|
|
309
|
+
plugin_classes = []
|
|
310
|
+
|
|
311
|
+
for module_name in self.discovered_modules:
|
|
312
|
+
try:
|
|
313
|
+
# Load each module and extract plugin classes
|
|
314
|
+
if self.load_module(module_name):
|
|
315
|
+
# Get all loaded plugin classes from this module
|
|
316
|
+
for class_name, class_obj in self.loaded_classes.items():
|
|
317
|
+
if class_obj not in plugin_classes:
|
|
318
|
+
plugin_classes.append(class_obj)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.warning(f"Failed to load plugin {module_name} for CLI arg discovery: {e}")
|
|
321
|
+
|
|
322
|
+
logger.info(f"CLI arg discovery: {len(plugin_classes)} plugin classes found")
|
|
323
|
+
return plugin_classes
|
|
290
324
|
|
|
291
325
|
def get_plugin_class(self, plugin_name: str) -> Type:
|
|
292
326
|
"""Get a loaded plugin class by name.
|
core/plugins/factory.py
CHANGED
|
@@ -26,21 +26,19 @@ class PluginFactory:
|
|
|
26
26
|
self,
|
|
27
27
|
plugin_class: Type,
|
|
28
28
|
plugin_name: str,
|
|
29
|
-
state_manager: Any,
|
|
30
29
|
event_bus: Any,
|
|
31
30
|
renderer: Any,
|
|
32
31
|
config: Any
|
|
33
32
|
) -> Any:
|
|
34
33
|
"""Instantiate a single plugin with dependencies.
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
Args:
|
|
37
36
|
plugin_class: The plugin class to instantiate.
|
|
38
37
|
plugin_name: Name of the plugin.
|
|
39
|
-
state_manager: State management system.
|
|
40
38
|
event_bus: Event bus for hook registration.
|
|
41
39
|
renderer: Terminal renderer.
|
|
42
40
|
config: Configuration manager.
|
|
43
|
-
|
|
41
|
+
|
|
44
42
|
Returns:
|
|
45
43
|
Plugin instance if successful, None otherwise.
|
|
46
44
|
"""
|
|
@@ -48,7 +46,7 @@ class PluginFactory:
|
|
|
48
46
|
if not has_method(plugin_class, '__init__'):
|
|
49
47
|
logger.debug(f"Plugin {plugin_name} is not instantiable (no __init__ method)")
|
|
50
48
|
return None
|
|
51
|
-
|
|
49
|
+
|
|
52
50
|
# Try to instantiate the plugin
|
|
53
51
|
# Clean plugin name: remove 'Plugin' suffix if present and use as name
|
|
54
52
|
clean_name = plugin_name
|
|
@@ -58,7 +56,6 @@ class PluginFactory:
|
|
|
58
56
|
instance = instantiate_plugin_safely(
|
|
59
57
|
plugin_class,
|
|
60
58
|
name=clean_name,
|
|
61
|
-
state_manager=state_manager,
|
|
62
59
|
event_bus=event_bus,
|
|
63
60
|
renderer=renderer,
|
|
64
61
|
config=config
|
|
@@ -78,30 +75,27 @@ class PluginFactory:
|
|
|
78
75
|
def instantiate_all(
|
|
79
76
|
self,
|
|
80
77
|
plugin_classes: Dict[str, Type],
|
|
81
|
-
state_manager: Any,
|
|
82
78
|
event_bus: Any,
|
|
83
79
|
renderer: Any,
|
|
84
80
|
config: Any
|
|
85
81
|
) -> Dict[str, Any]:
|
|
86
82
|
"""Instantiate all provided plugin classes.
|
|
87
|
-
|
|
83
|
+
|
|
88
84
|
Args:
|
|
89
85
|
plugin_classes: Dictionary mapping plugin names to classes.
|
|
90
|
-
state_manager: State management system.
|
|
91
86
|
event_bus: Event bus for hook registration.
|
|
92
87
|
renderer: Terminal renderer.
|
|
93
88
|
config: Configuration manager.
|
|
94
|
-
|
|
89
|
+
|
|
95
90
|
Returns:
|
|
96
91
|
Dictionary mapping plugin names to their instances.
|
|
97
92
|
"""
|
|
98
93
|
error_accumulator = ErrorAccumulator(logger)
|
|
99
|
-
|
|
94
|
+
|
|
100
95
|
for plugin_name, plugin_class in plugin_classes.items():
|
|
101
96
|
instance = self.instantiate_plugin(
|
|
102
97
|
plugin_class,
|
|
103
98
|
plugin_name,
|
|
104
|
-
state_manager,
|
|
105
99
|
event_bus,
|
|
106
100
|
renderer,
|
|
107
101
|
config
|
core/plugins/registry.py
CHANGED
|
@@ -110,34 +110,22 @@ class PluginRegistry:
|
|
|
110
110
|
"""
|
|
111
111
|
return list(self.discovery.loaded_classes.keys())
|
|
112
112
|
|
|
113
|
-
def instantiate_plugins(self,
|
|
113
|
+
def instantiate_plugins(self, event_bus, renderer, config) -> Dict[str, Any]:
|
|
114
114
|
"""Create instances of all registered plugins that can be instantiated.
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
Args:
|
|
117
|
-
state_manager: State management system.
|
|
118
117
|
event_bus: Event bus for hook registration.
|
|
119
118
|
renderer: Terminal renderer.
|
|
120
119
|
config: Configuration manager.
|
|
121
|
-
|
|
120
|
+
|
|
122
121
|
Returns:
|
|
123
122
|
Dictionary mapping plugin names to their instances.
|
|
124
123
|
"""
|
|
125
124
|
plugin_classes = self.discovery.loaded_classes
|
|
126
125
|
return self.factory.instantiate_all(
|
|
127
|
-
plugin_classes,
|
|
126
|
+
plugin_classes, event_bus, renderer, config
|
|
128
127
|
)
|
|
129
|
-
|
|
130
|
-
def collect_status_lines(self, plugin_instances: Dict[str, Any]) -> Dict[str, List[str]]:
|
|
131
|
-
"""Collect status lines from all plugins organized by area.
|
|
132
|
-
|
|
133
|
-
Args:
|
|
134
|
-
plugin_instances: Dictionary of plugin instances.
|
|
135
|
-
|
|
136
|
-
Returns:
|
|
137
|
-
Dictionary with areas A, B, C containing lists of status lines.
|
|
138
|
-
"""
|
|
139
|
-
return self.collector.collect_all_status(plugin_instances)
|
|
140
|
-
|
|
128
|
+
|
|
141
129
|
def get_registry_stats(self) -> Dict[str, Any]:
|
|
142
130
|
"""Get comprehensive statistics about the registry and its components.
|
|
143
131
|
|