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/config/loader.py
CHANGED
|
@@ -7,16 +7,44 @@ from importlib.metadata import version as get_version, PackageNotFoundError
|
|
|
7
7
|
|
|
8
8
|
from ..utils import deep_merge
|
|
9
9
|
from ..utils.error_utils import safe_execute, log_and_continue
|
|
10
|
-
from ..utils.config_utils import get_system_prompt_content
|
|
10
|
+
from ..utils.config_utils import get_system_prompt_content, get_project_data_dir
|
|
11
11
|
from ..utils.prompt_renderer import render_system_prompt
|
|
12
12
|
from .manager import ConfigManager
|
|
13
13
|
from .plugin_config_manager import PluginConfigManager
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
def _get_version_from_pyproject() -> str:
|
|
16
|
+
"""Read version from pyproject.toml for development mode."""
|
|
17
|
+
try:
|
|
18
|
+
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
|
19
|
+
if pyproject_path.exists():
|
|
20
|
+
content = pyproject_path.read_text()
|
|
21
|
+
for line in content.splitlines():
|
|
22
|
+
if line.startswith("version ="):
|
|
23
|
+
# Extract version from: version = "0.4.10"
|
|
24
|
+
return line.split("=")[1].strip().strip('"').strip("'")
|
|
25
|
+
except Exception:
|
|
26
|
+
pass
|
|
27
|
+
return None # Return None if not found
|
|
28
|
+
|
|
29
|
+
def _is_running_from_source() -> bool:
|
|
30
|
+
"""Check if we're running from source (development mode) vs installed package."""
|
|
31
|
+
try:
|
|
32
|
+
# If pyproject.toml exists in parent directory, we're running from source
|
|
33
|
+
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
|
34
|
+
return pyproject_path.exists()
|
|
35
|
+
except Exception:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
# Get version: prefer pyproject.toml when running from source, otherwise use installed version
|
|
39
|
+
if _is_running_from_source():
|
|
40
|
+
# Development mode: use pyproject.toml
|
|
41
|
+
_package_version = _get_version_from_pyproject() or "0.0.0"
|
|
42
|
+
else:
|
|
43
|
+
# Production mode: use installed package version
|
|
44
|
+
try:
|
|
45
|
+
_package_version = get_version("kollabor")
|
|
46
|
+
except PackageNotFoundError:
|
|
47
|
+
_package_version = "0.0.0"
|
|
20
48
|
|
|
21
49
|
logger = logging.getLogger(__name__)
|
|
22
50
|
|
|
@@ -113,7 +141,7 @@ class ConfigLoader:
|
|
|
113
141
|
},
|
|
114
142
|
"logging": {
|
|
115
143
|
"level": "INFO",
|
|
116
|
-
"file":
|
|
144
|
+
"file": None, # Determined dynamically by get_logs_dir()
|
|
117
145
|
"format_type": "compact",
|
|
118
146
|
"format": "%(asctime)s - %(levelname)-4s - %(message)-100s - %(filename)s:%(lineno)04d"
|
|
119
147
|
},
|
|
@@ -129,11 +157,8 @@ class ConfigLoader:
|
|
|
129
157
|
},
|
|
130
158
|
"core": {
|
|
131
159
|
"llm": {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
"model": "qwen/qwen3-4b",
|
|
135
|
-
"temperature": 0.7,
|
|
136
|
-
"timeout": 0,
|
|
160
|
+
# Note: api_url, api_token, model, temperature, timeout are now in profiles
|
|
161
|
+
# See core.llm.profiles.* for LLM connection settings
|
|
137
162
|
"max_history": 90,
|
|
138
163
|
"save_conversations": True,
|
|
139
164
|
"conversation_format": "jsonl",
|
|
@@ -146,11 +171,11 @@ class ConfigLoader:
|
|
|
146
171
|
"processing_delay": 0.1,
|
|
147
172
|
"thinking_delay": 0.3,
|
|
148
173
|
"api_poll_delay": 0.01,
|
|
149
|
-
"terminal_timeout":
|
|
174
|
+
"terminal_timeout": 120,
|
|
150
175
|
"mcp_timeout": 60,
|
|
151
176
|
"system_prompt": {
|
|
152
177
|
"base_prompt": system_prompt,
|
|
153
|
-
"include_project_structure":
|
|
178
|
+
"include_project_structure": False,
|
|
154
179
|
"attachment_files": [],
|
|
155
180
|
"custom_prompt_files": []
|
|
156
181
|
},
|
|
@@ -384,10 +409,11 @@ class ConfigLoader:
|
|
|
384
409
|
This is the main entry point for getting a fully merged configuration
|
|
385
410
|
that includes base defaults, plugin configs, and user overrides.
|
|
386
411
|
|
|
387
|
-
Priority order for user config:
|
|
388
|
-
1.
|
|
389
|
-
2.
|
|
390
|
-
3.
|
|
412
|
+
Priority order for user config (new layered system):
|
|
413
|
+
1. Global config (~/.kollabor-cli/config.json) - base layer
|
|
414
|
+
2. Project config (~/.kollabor-cli/projects/<encoded>/config.json) - project defaults
|
|
415
|
+
3. Local config (.kollabor-cli/config.json in current directory) - local override
|
|
416
|
+
4. Base defaults (if none exist)
|
|
391
417
|
|
|
392
418
|
Returns:
|
|
393
419
|
Complete merged configuration dictionary.
|
|
@@ -411,37 +437,81 @@ class ConfigLoader:
|
|
|
411
437
|
return base_config
|
|
412
438
|
|
|
413
439
|
def _load_user_config_with_fallback(self) -> Dict[str, Any]:
|
|
414
|
-
"""Load user configuration
|
|
440
|
+
"""Load user configuration with layered resolution.
|
|
415
441
|
|
|
416
|
-
Priority order:
|
|
417
|
-
1.
|
|
418
|
-
2. Global config (~/.kollabor-cli/config.json)
|
|
442
|
+
Priority order (new layered system):
|
|
443
|
+
1. Explicit config_manager.config_path (if provided and exists)
|
|
444
|
+
2. Global config (~/.kollabor-cli/config.json) - base layer
|
|
445
|
+
3. Project config (~/.kollabor-cli/projects/<encoded>/config.json) - project defaults
|
|
446
|
+
4. Local config (.kollabor-cli/config.json) - local override
|
|
447
|
+
|
|
448
|
+
Each layer is merged on top of the previous one using deep_merge.
|
|
419
449
|
|
|
420
450
|
Returns:
|
|
421
|
-
|
|
451
|
+
Merged user configuration dictionary, or empty dict if none found.
|
|
422
452
|
"""
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
453
|
+
import json
|
|
454
|
+
|
|
455
|
+
merged_config = {}
|
|
456
|
+
|
|
457
|
+
# Check if an explicit config path was provided (e.g., for testing)
|
|
458
|
+
explicit_path = None
|
|
459
|
+
if self.config_manager and self.config_manager.config_path:
|
|
460
|
+
explicit_path = self.config_manager.config_path
|
|
461
|
+
# If explicit path exists and is not in standard locations, load only from it
|
|
462
|
+
standard_paths = [
|
|
463
|
+
Path.home() / ".kollabor-cli" / "config.json",
|
|
464
|
+
get_project_data_dir() / "config.json",
|
|
465
|
+
Path.cwd() / ".kollabor-cli" / "config.json",
|
|
466
|
+
]
|
|
467
|
+
if explicit_path.exists() and explicit_path not in standard_paths:
|
|
468
|
+
try:
|
|
469
|
+
with open(explicit_path, 'r') as f:
|
|
470
|
+
return json.load(f) or {}
|
|
471
|
+
except Exception as e:
|
|
472
|
+
logger.warning(f"Failed to load explicit config: {e}")
|
|
473
|
+
return {}
|
|
474
|
+
|
|
475
|
+
# Layer 1: Global config (base)
|
|
431
476
|
global_config_path = Path.home() / ".kollabor-cli" / "config.json"
|
|
432
477
|
if global_config_path.exists():
|
|
433
478
|
try:
|
|
434
|
-
import json
|
|
435
479
|
with open(global_config_path, 'r') as f:
|
|
436
480
|
global_config = json.load(f)
|
|
437
481
|
if global_config:
|
|
438
|
-
|
|
439
|
-
|
|
482
|
+
merged_config = global_config
|
|
483
|
+
logger.debug(f"Loaded global config from: {global_config_path}")
|
|
440
484
|
except Exception as e:
|
|
441
485
|
logger.warning(f"Failed to load global config: {e}")
|
|
442
486
|
|
|
443
|
-
|
|
444
|
-
|
|
487
|
+
# Layer 2: Project config (defaults for this project)
|
|
488
|
+
project_config_path = get_project_data_dir() / "config.json"
|
|
489
|
+
if project_config_path.exists():
|
|
490
|
+
try:
|
|
491
|
+
with open(project_config_path, 'r') as f:
|
|
492
|
+
project_config = json.load(f)
|
|
493
|
+
if project_config:
|
|
494
|
+
merged_config = deep_merge(merged_config, project_config)
|
|
495
|
+
logger.debug(f"Merged project config from: {project_config_path}")
|
|
496
|
+
except Exception as e:
|
|
497
|
+
logger.warning(f"Failed to load project config: {e}")
|
|
498
|
+
|
|
499
|
+
# Layer 3: Local config (override)
|
|
500
|
+
local_config_path = Path.cwd() / ".kollabor-cli" / "config.json"
|
|
501
|
+
if local_config_path.exists():
|
|
502
|
+
try:
|
|
503
|
+
with open(local_config_path, 'r') as f:
|
|
504
|
+
local_config = json.load(f)
|
|
505
|
+
if local_config:
|
|
506
|
+
merged_config = deep_merge(merged_config, local_config)
|
|
507
|
+
logger.debug(f"Merged local config from: {local_config_path}")
|
|
508
|
+
except Exception as e:
|
|
509
|
+
logger.warning(f"Failed to load local config: {e}")
|
|
510
|
+
|
|
511
|
+
if not merged_config:
|
|
512
|
+
logger.debug("No user configuration found (global, project, or local)")
|
|
513
|
+
|
|
514
|
+
return merged_config
|
|
445
515
|
|
|
446
516
|
def save_merged_config(self, config: Dict[str, Any]) -> bool:
|
|
447
517
|
"""Save the complete merged configuration to file.
|
|
@@ -449,6 +519,11 @@ class ConfigLoader:
|
|
|
449
519
|
Note: base_prompt is excluded from saving because it should always
|
|
450
520
|
be dynamically loaded from the system_prompt/*.md files on startup.
|
|
451
521
|
|
|
522
|
+
Save path determination (new layered system):
|
|
523
|
+
1. Local .kollabor-cli/config.json (if exists) - local override
|
|
524
|
+
2. Project config (if exists) - project defaults
|
|
525
|
+
3. Global config - fallback
|
|
526
|
+
|
|
452
527
|
Args:
|
|
453
528
|
config: Configuration dictionary to save.
|
|
454
529
|
|
|
@@ -456,6 +531,7 @@ class ConfigLoader:
|
|
|
456
531
|
True if save successful, False otherwise.
|
|
457
532
|
"""
|
|
458
533
|
import copy
|
|
534
|
+
import json
|
|
459
535
|
config_to_save = copy.deepcopy(config)
|
|
460
536
|
|
|
461
537
|
# Remove base_prompt - it should always be loaded fresh from .md files
|
|
@@ -466,7 +542,45 @@ class ConfigLoader:
|
|
|
466
542
|
except (KeyError, TypeError):
|
|
467
543
|
pass # Config structure doesn't match expected format
|
|
468
544
|
|
|
469
|
-
|
|
545
|
+
# Use the config_manager's path if available, otherwise determine from layered system
|
|
546
|
+
if self.config_manager and self.config_manager.config_path:
|
|
547
|
+
save_path = self.config_manager.config_path
|
|
548
|
+
else:
|
|
549
|
+
save_path = self._get_config_save_path()
|
|
550
|
+
save_path.parent.mkdir(parents=True, exist_ok=True)
|
|
551
|
+
|
|
552
|
+
try:
|
|
553
|
+
with open(save_path, 'w') as f:
|
|
554
|
+
json.dump(config_to_save, f, indent=2, ensure_ascii=False)
|
|
555
|
+
logger.info(f"Saved configuration to: {save_path}")
|
|
556
|
+
return True
|
|
557
|
+
except Exception as e:
|
|
558
|
+
logger.error(f"Failed to save configuration to {save_path}: {e}")
|
|
559
|
+
return False
|
|
560
|
+
|
|
561
|
+
def _get_config_save_path(self) -> Path:
|
|
562
|
+
"""Determine the appropriate config save path.
|
|
563
|
+
|
|
564
|
+
Priority:
|
|
565
|
+
1. Local .kollabor-cli/config.json (if exists) - local override
|
|
566
|
+
2. Project config (if exists) - project defaults
|
|
567
|
+
3. Global config - fallback
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
Path where config should be saved.
|
|
571
|
+
"""
|
|
572
|
+
# Check local override
|
|
573
|
+
local_path = Path.cwd() / ".kollabor-cli" / "config.json"
|
|
574
|
+
if local_path.exists():
|
|
575
|
+
return local_path
|
|
576
|
+
|
|
577
|
+
# Check project config
|
|
578
|
+
project_path = get_project_data_dir() / "config.json"
|
|
579
|
+
if project_path.exists():
|
|
580
|
+
return project_path
|
|
581
|
+
|
|
582
|
+
# Default to global
|
|
583
|
+
return Path.home() / ".kollabor-cli" / "config.json"
|
|
470
584
|
|
|
471
585
|
def update_with_plugins(self) -> bool:
|
|
472
586
|
"""Update the configuration file with newly discovered plugins.
|
core/config/service.py
CHANGED
|
@@ -141,18 +141,30 @@ class ConfigService:
|
|
|
141
141
|
|
|
142
142
|
def set(self, key_path: str, value: Any) -> bool:
|
|
143
143
|
"""Set a configuration value using dot notation.
|
|
144
|
-
|
|
144
|
+
|
|
145
|
+
Saves to the appropriate location based on the layered config system:
|
|
146
|
+
1. Local .kollabor-cli/config.json (if exists)
|
|
147
|
+
2. Project config (if exists)
|
|
148
|
+
3. Global config (fallback)
|
|
149
|
+
|
|
145
150
|
Args:
|
|
146
151
|
key_path: Dot-separated path to the config value.
|
|
147
152
|
value: Value to set.
|
|
148
|
-
|
|
153
|
+
|
|
149
154
|
Returns:
|
|
150
155
|
True if set successful, False otherwise.
|
|
151
156
|
"""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
from ..utils import safe_set
|
|
158
|
+
|
|
159
|
+
if safe_set(self.config_manager.config, key_path, value):
|
|
160
|
+
# Use the loader's save mechanism which respects the layered system
|
|
161
|
+
success = self.config_loader.save_merged_config(self.config_manager.config)
|
|
162
|
+
if success:
|
|
163
|
+
logger.debug(f"Configuration updated: {key_path}")
|
|
164
|
+
return True
|
|
165
|
+
|
|
166
|
+
logger.error(f"Failed to set config key: {key_path}")
|
|
167
|
+
return False
|
|
156
168
|
|
|
157
169
|
def reload(self) -> bool:
|
|
158
170
|
"""Reload configuration from file and plugins.
|
core/events/bus.py
CHANGED
|
@@ -1,36 +1,56 @@
|
|
|
1
1
|
"""Event system for plugin communication."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Any, Dict
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
5
|
|
|
6
6
|
from .models import EventType, Hook
|
|
7
7
|
from .registry import HookRegistry
|
|
8
|
-
from .executor import HookExecutor
|
|
9
8
|
from .processor import EventProcessor
|
|
10
9
|
|
|
11
10
|
logger = logging.getLogger(__name__)
|
|
12
11
|
|
|
12
|
+
# Import constants after HookExecutor to avoid circular import
|
|
13
|
+
from .executor import (
|
|
14
|
+
HookExecutor,
|
|
15
|
+
DEFAULT_HOOK_TIMEOUT,
|
|
16
|
+
DEFAULT_HOOK_RETRIES,
|
|
17
|
+
DEFAULT_ERROR_ACTION,
|
|
18
|
+
ABSOLUTE_MAX_RETRIES,
|
|
19
|
+
MIN_TIMEOUT,
|
|
20
|
+
MAX_TIMEOUT,
|
|
21
|
+
VALID_ERROR_ACTIONS
|
|
22
|
+
)
|
|
23
|
+
|
|
13
24
|
|
|
14
25
|
class EventBus:
|
|
15
26
|
"""Simplified event bus system for plugin communication.
|
|
16
|
-
|
|
27
|
+
|
|
17
28
|
Coordinates between specialized components for hook registration
|
|
18
29
|
and event processing with clean separation of concerns.
|
|
19
30
|
"""
|
|
20
|
-
|
|
21
|
-
def __init__(self) -> None:
|
|
22
|
-
"""Initialize the event bus with specialized components.
|
|
31
|
+
|
|
32
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
33
|
+
"""Initialize the event bus with specialized components.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config: Configuration dictionary for hook defaults.
|
|
37
|
+
"""
|
|
38
|
+
self.config = config or {}
|
|
23
39
|
self.hook_registry = HookRegistry()
|
|
24
|
-
self.hook_executor = HookExecutor()
|
|
40
|
+
self.hook_executor = HookExecutor(config=self.config)
|
|
25
41
|
self.event_processor = EventProcessor(self.hook_registry, self.hook_executor)
|
|
26
42
|
logger.info("Event bus initialized with specialized components")
|
|
27
43
|
|
|
28
44
|
async def register_hook(self, hook: Hook) -> bool:
|
|
29
45
|
"""Register a hook with the event bus.
|
|
30
|
-
|
|
46
|
+
|
|
47
|
+
Note: Config defaults are applied during execution in HookExecutor,
|
|
48
|
+
not during registration. This allows runtime config changes to take
|
|
49
|
+
effect immediately without re-registering hooks.
|
|
50
|
+
|
|
31
51
|
Args:
|
|
32
52
|
hook: The hook to register.
|
|
33
|
-
|
|
53
|
+
|
|
34
54
|
Returns:
|
|
35
55
|
True if registration successful, False otherwise.
|
|
36
56
|
"""
|