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.
Files changed (128) hide show
  1. core/__init__.py +18 -0
  2. core/application.py +578 -0
  3. core/cli.py +193 -0
  4. core/commands/__init__.py +43 -0
  5. core/commands/executor.py +277 -0
  6. core/commands/menu_renderer.py +319 -0
  7. core/commands/parser.py +186 -0
  8. core/commands/registry.py +331 -0
  9. core/commands/system_commands.py +479 -0
  10. core/config/__init__.py +7 -0
  11. core/config/llm_task_config.py +110 -0
  12. core/config/loader.py +501 -0
  13. core/config/manager.py +112 -0
  14. core/config/plugin_config_manager.py +346 -0
  15. core/config/plugin_schema.py +424 -0
  16. core/config/service.py +399 -0
  17. core/effects/__init__.py +1 -0
  18. core/events/__init__.py +12 -0
  19. core/events/bus.py +129 -0
  20. core/events/executor.py +154 -0
  21. core/events/models.py +258 -0
  22. core/events/processor.py +176 -0
  23. core/events/registry.py +289 -0
  24. core/fullscreen/__init__.py +19 -0
  25. core/fullscreen/command_integration.py +290 -0
  26. core/fullscreen/components/__init__.py +12 -0
  27. core/fullscreen/components/animation.py +258 -0
  28. core/fullscreen/components/drawing.py +160 -0
  29. core/fullscreen/components/matrix_components.py +177 -0
  30. core/fullscreen/manager.py +302 -0
  31. core/fullscreen/plugin.py +204 -0
  32. core/fullscreen/renderer.py +282 -0
  33. core/fullscreen/session.py +324 -0
  34. core/io/__init__.py +52 -0
  35. core/io/buffer_manager.py +362 -0
  36. core/io/config_status_view.py +272 -0
  37. core/io/core_status_views.py +410 -0
  38. core/io/input_errors.py +313 -0
  39. core/io/input_handler.py +2655 -0
  40. core/io/input_mode_manager.py +402 -0
  41. core/io/key_parser.py +344 -0
  42. core/io/layout.py +587 -0
  43. core/io/message_coordinator.py +204 -0
  44. core/io/message_renderer.py +601 -0
  45. core/io/modal_interaction_handler.py +315 -0
  46. core/io/raw_input_processor.py +946 -0
  47. core/io/status_renderer.py +845 -0
  48. core/io/terminal_renderer.py +586 -0
  49. core/io/terminal_state.py +551 -0
  50. core/io/visual_effects.py +734 -0
  51. core/llm/__init__.py +26 -0
  52. core/llm/api_communication_service.py +863 -0
  53. core/llm/conversation_logger.py +473 -0
  54. core/llm/conversation_manager.py +414 -0
  55. core/llm/file_operations_executor.py +1401 -0
  56. core/llm/hook_system.py +402 -0
  57. core/llm/llm_service.py +1629 -0
  58. core/llm/mcp_integration.py +386 -0
  59. core/llm/message_display_service.py +450 -0
  60. core/llm/model_router.py +214 -0
  61. core/llm/plugin_sdk.py +396 -0
  62. core/llm/response_parser.py +848 -0
  63. core/llm/response_processor.py +364 -0
  64. core/llm/tool_executor.py +520 -0
  65. core/logging/__init__.py +19 -0
  66. core/logging/setup.py +208 -0
  67. core/models/__init__.py +5 -0
  68. core/models/base.py +23 -0
  69. core/plugins/__init__.py +13 -0
  70. core/plugins/collector.py +212 -0
  71. core/plugins/discovery.py +386 -0
  72. core/plugins/factory.py +263 -0
  73. core/plugins/registry.py +152 -0
  74. core/storage/__init__.py +5 -0
  75. core/storage/state_manager.py +84 -0
  76. core/ui/__init__.py +6 -0
  77. core/ui/config_merger.py +176 -0
  78. core/ui/config_widgets.py +369 -0
  79. core/ui/live_modal_renderer.py +276 -0
  80. core/ui/modal_actions.py +162 -0
  81. core/ui/modal_overlay_renderer.py +373 -0
  82. core/ui/modal_renderer.py +591 -0
  83. core/ui/modal_state_manager.py +443 -0
  84. core/ui/widget_integration.py +222 -0
  85. core/ui/widgets/__init__.py +27 -0
  86. core/ui/widgets/base_widget.py +136 -0
  87. core/ui/widgets/checkbox.py +85 -0
  88. core/ui/widgets/dropdown.py +140 -0
  89. core/ui/widgets/label.py +78 -0
  90. core/ui/widgets/slider.py +185 -0
  91. core/ui/widgets/text_input.py +224 -0
  92. core/utils/__init__.py +11 -0
  93. core/utils/config_utils.py +656 -0
  94. core/utils/dict_utils.py +212 -0
  95. core/utils/error_utils.py +275 -0
  96. core/utils/key_reader.py +171 -0
  97. core/utils/plugin_utils.py +267 -0
  98. core/utils/prompt_renderer.py +151 -0
  99. kollabor-0.4.9.dist-info/METADATA +298 -0
  100. kollabor-0.4.9.dist-info/RECORD +128 -0
  101. kollabor-0.4.9.dist-info/WHEEL +5 -0
  102. kollabor-0.4.9.dist-info/entry_points.txt +2 -0
  103. kollabor-0.4.9.dist-info/licenses/LICENSE +21 -0
  104. kollabor-0.4.9.dist-info/top_level.txt +4 -0
  105. kollabor_cli_main.py +20 -0
  106. plugins/__init__.py +1 -0
  107. plugins/enhanced_input/__init__.py +18 -0
  108. plugins/enhanced_input/box_renderer.py +103 -0
  109. plugins/enhanced_input/box_styles.py +142 -0
  110. plugins/enhanced_input/color_engine.py +165 -0
  111. plugins/enhanced_input/config.py +150 -0
  112. plugins/enhanced_input/cursor_manager.py +72 -0
  113. plugins/enhanced_input/geometry.py +81 -0
  114. plugins/enhanced_input/state.py +130 -0
  115. plugins/enhanced_input/text_processor.py +115 -0
  116. plugins/enhanced_input_plugin.py +385 -0
  117. plugins/fullscreen/__init__.py +9 -0
  118. plugins/fullscreen/example_plugin.py +327 -0
  119. plugins/fullscreen/matrix_plugin.py +132 -0
  120. plugins/hook_monitoring_plugin.py +1299 -0
  121. plugins/query_enhancer_plugin.py +350 -0
  122. plugins/save_conversation_plugin.py +502 -0
  123. plugins/system_commands_plugin.py +93 -0
  124. plugins/tmux_plugin.py +795 -0
  125. plugins/workflow_enforcement_plugin.py +629 -0
  126. system_prompt/default.md +1286 -0
  127. system_prompt/default_win.md +265 -0
  128. system_prompt/example_with_trender.md +47 -0
@@ -0,0 +1,346 @@
1
+ """Plugin configuration manager for dynamic schema registration and widget generation."""
2
+
3
+ import logging
4
+ from typing import Any, Dict, List, Optional, Type
5
+ from pathlib import Path
6
+
7
+ from .plugin_schema import PluginConfigSchema, ConfigField, WidgetType
8
+ from ..plugins.discovery import PluginDiscovery
9
+ from ..utils.plugin_utils import get_plugin_config_safely, has_method
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class PluginConfigManager:
15
+ """Manages dynamic plugin configuration schemas and widget generation.
16
+
17
+ This manager coordinates between the plugin discovery system and the
18
+ configuration UI system to automatically generate widgets for plugin
19
+ configuration based on plugin-defined schemas.
20
+ """
21
+
22
+ def __init__(self, plugin_discovery: PluginDiscovery):
23
+ """Initialize the plugin config manager.
24
+
25
+ Args:
26
+ plugin_discovery: Plugin discovery instance for accessing loaded plugins.
27
+ """
28
+ self.plugin_discovery = plugin_discovery
29
+ self.plugin_schemas: Dict[str, PluginConfigSchema] = {}
30
+ self.widget_definitions: List[Dict[str, Any]] = []
31
+ logger.info("PluginConfigManager initialized")
32
+
33
+ def register_plugin_schema(self, plugin_name: str, schema: PluginConfigSchema) -> None:
34
+ """Register a plugin's configuration schema.
35
+
36
+ Args:
37
+ plugin_name: Name of the plugin.
38
+ schema: Plugin configuration schema.
39
+ """
40
+ self.plugin_schemas[plugin_name] = schema
41
+ logger.info(f"Registered config schema for plugin: {plugin_name}")
42
+
43
+ # Update widget definitions
44
+ self._rebuild_widget_definitions()
45
+
46
+ def discover_plugin_schemas(self) -> None:
47
+ """Discover and register schemas from all loaded plugins."""
48
+ logger.info("Discovering plugin configuration schemas...")
49
+
50
+ for plugin_name, plugin_class in self.plugin_discovery.loaded_classes.items():
51
+ try:
52
+ # Check if plugin has a get_config_schema method
53
+ if has_method(plugin_class, "get_config_schema"):
54
+ logger.debug(f"Plugin {plugin_name} has get_config_schema method")
55
+
56
+ # Get schema from plugin
57
+ schema = plugin_class.get_config_schema()
58
+
59
+ if isinstance(schema, PluginConfigSchema):
60
+ self.register_plugin_schema(plugin_name, schema)
61
+ else:
62
+ logger.warning(f"Plugin {plugin_name} returned invalid schema type: {type(schema)}")
63
+
64
+ # Fallback: try to create schema from get_default_config
65
+ elif has_method(plugin_class, "get_default_config"):
66
+ logger.debug(f"Creating schema from default config for plugin: {plugin_name}")
67
+ schema = self._create_schema_from_default_config(plugin_name, plugin_class)
68
+ if schema:
69
+ self.register_plugin_schema(plugin_name, schema)
70
+ else:
71
+ logger.debug(f"Plugin {plugin_name} has no configuration schema")
72
+
73
+ except Exception as e:
74
+ logger.error(f"Failed to discover schema for plugin {plugin_name}: {e}")
75
+
76
+ logger.info(f"Discovered schemas for {len(self.plugin_schemas)} plugins")
77
+
78
+ def _create_schema_from_default_config(self, plugin_name: str, plugin_class: Type) -> Optional[PluginConfigSchema]:
79
+ """Create a basic schema from a plugin's default config.
80
+
81
+ Args:
82
+ plugin_name: Name of the plugin.
83
+ plugin_class: Plugin class.
84
+
85
+ Returns:
86
+ Basic schema if successful, None otherwise.
87
+ """
88
+ try:
89
+ default_config = get_plugin_config_safely(plugin_class)
90
+ if not default_config:
91
+ return None
92
+
93
+ from .plugin_schema import ConfigSchemaBuilder, WidgetType, ValidationType
94
+
95
+ builder = ConfigSchemaBuilder(plugin_name, f"Auto-generated schema for {plugin_name}")
96
+
97
+ # Add 'enabled' field if present
98
+ if 'enabled' in default_config:
99
+ builder.add_checkbox(
100
+ key="enabled",
101
+ label="Enabled",
102
+ default=default_config['enabled'],
103
+ help_text="Enable or disable this plugin"
104
+ )
105
+
106
+ # Add other fields with basic type inference
107
+ for key, value in default_config.items():
108
+ if key == 'enabled':
109
+ continue # Already handled
110
+
111
+ if isinstance(value, bool):
112
+ builder.add_checkbox(
113
+ key=key,
114
+ label=key.replace('_', ' ').title(),
115
+ default=value,
116
+ help_text=f"Configuration option: {key}"
117
+ )
118
+ elif isinstance(value, (int, float)):
119
+ if isinstance(value, int):
120
+ builder.add_slider(
121
+ key=key,
122
+ label=key.replace('_', ' ').title(),
123
+ default=value,
124
+ min_value=0,
125
+ max_value=max(100, value * 2),
126
+ help_text=f"Numeric configuration: {key}"
127
+ )
128
+ else:
129
+ builder.add_slider(
130
+ key=key,
131
+ label=key.replace('_', ' ').title(),
132
+ default=value,
133
+ min_value=0.0,
134
+ max_value=max(1.0, value * 2),
135
+ step=0.1,
136
+ help_text=f"Float configuration: {key}"
137
+ )
138
+ elif isinstance(value, str):
139
+ builder.add_text_input(
140
+ key=key,
141
+ label=key.replace('_', ' ').title(),
142
+ default=value,
143
+ help_text=f"Text configuration: {key}"
144
+ )
145
+ elif isinstance(value, list):
146
+ # For lists, assume it's a dropdown of options
147
+ if len(value) <= 10: # Reasonable limit for dropdown
148
+ builder.add_dropdown(
149
+ key=key,
150
+ label=key.replace('_', ' ').title(),
151
+ options=value,
152
+ default=value[0] if value else "",
153
+ help_text=f"Select from options: {key}"
154
+ )
155
+ else:
156
+ builder.add_text_input(
157
+ key=key,
158
+ label=key.replace('_', ' ').title(),
159
+ default=str(value),
160
+ help_text=f"List configuration: {key}"
161
+ )
162
+ elif isinstance(value, dict):
163
+ # For nested dicts, create a text input with JSON
164
+ builder.add_text_input(
165
+ key=key,
166
+ label=key.replace('_', ' ').title(),
167
+ default=str(value),
168
+ validation_type=ValidationType.JSON,
169
+ help_text=f"JSON configuration: {key}"
170
+ )
171
+
172
+ return builder.build()
173
+
174
+ except Exception as e:
175
+ logger.error(f"Failed to create schema from default config for {plugin_name}: {e}")
176
+ return None
177
+
178
+ def get_plugin_schema(self, plugin_name: str) -> Optional[PluginConfigSchema]:
179
+ """Get the configuration schema for a specific plugin.
180
+
181
+ Args:
182
+ plugin_name: Name of the plugin.
183
+
184
+ Returns:
185
+ Plugin schema if found, None otherwise.
186
+ """
187
+ return self.plugin_schemas.get(plugin_name)
188
+
189
+ def get_all_schemas(self) -> Dict[str, PluginConfigSchema]:
190
+ """Get all registered plugin schemas.
191
+
192
+ Returns:
193
+ Dictionary mapping plugin names to their schemas.
194
+ """
195
+ return self.plugin_schemas.copy()
196
+
197
+ def _rebuild_widget_definitions(self) -> None:
198
+ """Rebuild the complete widget definitions list."""
199
+ self.widget_definitions = []
200
+
201
+ for plugin_name, schema in self.plugin_schemas.items():
202
+ plugin_widgets = schema.to_widget_definitions()
203
+ self.widget_definitions.extend(plugin_widgets)
204
+ logger.debug(f"Added {len(plugin_widgets)} widgets for plugin: {plugin_name}")
205
+
206
+ logger.info(f"Rebuilt widget definitions: {len(self.widget_definitions)} total widgets")
207
+
208
+ def get_widget_definitions(self) -> List[Dict[str, Any]]:
209
+ """Get all widget definitions for all registered plugins.
210
+
211
+ Returns:
212
+ List of widget definition dictionaries.
213
+ """
214
+ if not self.widget_definitions:
215
+ self._rebuild_widget_definitions()
216
+
217
+ return self.widget_definitions.copy()
218
+
219
+ def get_plugin_config_sections(self) -> List[Dict[str, Any]]:
220
+ """Get UI sections for plugin configuration.
221
+
222
+ Returns:
223
+ List of section definitions for the configuration UI.
224
+ """
225
+ sections = []
226
+
227
+ # Group plugins by category
228
+ plugins_by_category = {}
229
+ for plugin_name, schema in self.plugin_schemas.items():
230
+ for category in schema.categories:
231
+ if category not in plugins_by_category:
232
+ plugins_by_category[category] = []
233
+ plugins_by_category[category].append((plugin_name, schema))
234
+
235
+ # Create sections for each category
236
+ for category, plugins in plugins_by_category.items():
237
+ category_widgets = []
238
+
239
+ for plugin_name, schema in plugins:
240
+ plugin_widgets = schema.to_widget_definitions()
241
+ # Add plugin name to each widget for identification
242
+ for widget in plugin_widgets:
243
+ widget["plugin_name"] = plugin_name
244
+ category_widgets.extend(plugin_widgets)
245
+
246
+ if category_widgets:
247
+ sections.append({
248
+ "title": f"{category} Plugins",
249
+ "widgets": category_widgets
250
+ })
251
+
252
+ return sections
253
+
254
+ def validate_plugin_config(self, plugin_name: str, config: Dict[str, Any]) -> Dict[str, Any]:
255
+ """Validate a plugin's configuration against its schema.
256
+
257
+ Args:
258
+ plugin_name: Name of the plugin.
259
+ config: Configuration to validate.
260
+
261
+ Returns:
262
+ Validation result dictionary.
263
+ """
264
+ schema = self.get_plugin_schema(plugin_name)
265
+ if not schema:
266
+ return {
267
+ "valid": False,
268
+ "errors": {"schema": f"No schema found for plugin: {plugin_name}"}
269
+ }
270
+
271
+ return schema.validate_config(config)
272
+
273
+ def get_plugin_default_config(self, plugin_name: str) -> Dict[str, Any]:
274
+ """Get the default configuration for a plugin.
275
+
276
+ Args:
277
+ plugin_name: Name of the plugin.
278
+
279
+ Returns:
280
+ Default configuration dictionary.
281
+ """
282
+ schema = self.get_plugin_schema(plugin_name)
283
+ if not schema:
284
+ return {}
285
+
286
+ return schema.get_default_config()
287
+
288
+ def merge_plugin_configs(self) -> Dict[str, Any]:
289
+ """Merge all plugin configurations into a single dictionary.
290
+
291
+ Returns:
292
+ Merged configuration dictionary with all plugin configs.
293
+ """
294
+ merged_config = {}
295
+
296
+ for plugin_name, schema in self.plugin_schemas.items():
297
+ plugin_config = schema.get_default_config()
298
+ if plugin_config:
299
+ merged_config[plugin_name] = plugin_config
300
+
301
+ return merged_config
302
+
303
+ def get_stats(self) -> Dict[str, Any]:
304
+ """Get statistics about the plugin configuration system.
305
+
306
+ Returns:
307
+ Statistics dictionary.
308
+ """
309
+ total_fields = sum(len(schema.fields) for schema in self.plugin_schemas.values())
310
+ total_widgets = len(self.widget_definitions)
311
+
312
+ widget_type_counts = {}
313
+ for widget_def in self.widget_definitions:
314
+ widget_type = widget_def.get("type", "unknown")
315
+ widget_type_counts[widget_type] = widget_type_counts.get(widget_type, 0) + 1
316
+
317
+ return {
318
+ "registered_plugins": len(self.plugin_schemas),
319
+ "total_fields": total_fields,
320
+ "total_widgets": total_widgets,
321
+ "widget_types": widget_type_counts,
322
+ "categories": list(set(
323
+ category
324
+ for schema in self.plugin_schemas.values()
325
+ for category in schema.categories
326
+ ))
327
+ }
328
+
329
+
330
+ # Global instance for easy access
331
+ _plugin_config_manager: Optional[PluginConfigManager] = None
332
+
333
+
334
+ def get_plugin_config_manager(plugin_discovery: PluginDiscovery) -> PluginConfigManager:
335
+ """Get or create the global plugin config manager instance.
336
+
337
+ Args:
338
+ plugin_discovery: Plugin discovery instance.
339
+
340
+ Returns:
341
+ PluginConfigManager instance.
342
+ """
343
+ global _plugin_config_manager
344
+ if _plugin_config_manager is None:
345
+ _plugin_config_manager = PluginConfigManager(plugin_discovery)
346
+ return _plugin_config_manager