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
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
<!-- Configuration integrity validation - check settings, detect conflicts, verify defaults -->
|
|
2
|
+
|
|
3
|
+
skill name: validate-config
|
|
4
|
+
|
|
5
|
+
purpose:
|
|
6
|
+
validate kollabor configuration integrity, check for missing required settings,
|
|
7
|
+
identify conflicting configurations, and show effective (merged) configuration.
|
|
8
|
+
helps diagnose configuration-related issues before they cause runtime problems.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
when to use:
|
|
12
|
+
[ ] application behaving unexpectedly
|
|
13
|
+
[ ] plugin not loading properly
|
|
14
|
+
[ ] changes to config.json not taking effect
|
|
15
|
+
[ ] want to understand effective vs default config
|
|
16
|
+
[ ] setting up kollabor for first time
|
|
17
|
+
[ ] migrating between versions
|
|
18
|
+
[ ] diagnosing plugin configuration issues
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
methodology:
|
|
22
|
+
|
|
23
|
+
phase 1: config file discovery and structure validation
|
|
24
|
+
locate all config files (local, global, plugin defaults)
|
|
25
|
+
validate json syntax and structure
|
|
26
|
+
check required top-level sections
|
|
27
|
+
|
|
28
|
+
phase 2: setting validation
|
|
29
|
+
verify required llm settings (api_url, model, etc)
|
|
30
|
+
check plugin configurations
|
|
31
|
+
validate data types and value ranges
|
|
32
|
+
identify deprecated or moved settings
|
|
33
|
+
|
|
34
|
+
phase 3: conflict detection
|
|
35
|
+
check for duplicate settings with different values
|
|
36
|
+
identify plugin config conflicts
|
|
37
|
+
detect incompatible setting combinations
|
|
38
|
+
|
|
39
|
+
phase 4: effective config analysis
|
|
40
|
+
show merged configuration (defaults + plugins + user)
|
|
41
|
+
identify which file/layer provides each setting
|
|
42
|
+
highlight user overrides
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
tools and commands:
|
|
46
|
+
|
|
47
|
+
core files to read:
|
|
48
|
+
<read>file>core/config/loader.py</file>
|
|
49
|
+
<read>file>core/config/manager.py</file>
|
|
50
|
+
<read>file>core/config/plugin_config_manager.py</file>
|
|
51
|
+
<read>file>core/config/plugin_schema.py</file>
|
|
52
|
+
<read>file>core/utils/config_utils.py</file>
|
|
53
|
+
|
|
54
|
+
check config file existence:
|
|
55
|
+
<terminal>ls -la .kollabor-cli/config.json 2>/dev/null || echo "no local config"</terminal>
|
|
56
|
+
<terminal>ls -la ~/.kollabor-cli/config.json 2>/dev/null || echo "no global config"</terminal>
|
|
57
|
+
|
|
58
|
+
view config files:
|
|
59
|
+
<terminal>cat .kollabor-cli/config.json 2>/dev/null</terminal>
|
|
60
|
+
<terminal>cat ~/.kollabor-cli/config.json 2>/dev/null</terminal>
|
|
61
|
+
|
|
62
|
+
validate json syntax:
|
|
63
|
+
<terminal>python -c "import json; json.load(open('.kollabor-cli/config.json'))" 2>&1</terminal>
|
|
64
|
+
<terminal>python -c "import json; json.load(open('~/.kollabor-cli/config.json'))" 2>&1</terminal>
|
|
65
|
+
|
|
66
|
+
find all config-related files:
|
|
67
|
+
<terminal>find .kollabor-cli -name "*.json" -type f 2>/dev/null</terminal>
|
|
68
|
+
<terminal>find ~/.kollabor-cli -name "*.json" -type f 2>/dev/null</terminal>
|
|
69
|
+
|
|
70
|
+
check config in logs:
|
|
71
|
+
<terminal>grep -i "config" .kollabor-cli/logs/kollabor.log | tail -20</terminal>
|
|
72
|
+
<terminal>grep -i "loaded.*config\|merged.*config" .kollabor-cli/logs/kollabor.log</terminal>
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
configuration system architecture:
|
|
76
|
+
|
|
77
|
+
config manager (core/config/manager.py)
|
|
78
|
+
- config_path: path to config.json file
|
|
79
|
+
- config: in-memory configuration dict
|
|
80
|
+
- load_config_file(): load json from file
|
|
81
|
+
- save_config_file(): save json to file
|
|
82
|
+
- get(key_path, default): dot notation access
|
|
83
|
+
- set(key_path, value): dot notation write
|
|
84
|
+
|
|
85
|
+
config loader (core/config/loader.py)
|
|
86
|
+
- config_manager: base config manager instance
|
|
87
|
+
- plugin_registry: plugin registry for plugin configs
|
|
88
|
+
- plugin_config_manager: dynamic schema manager
|
|
89
|
+
- get_base_config(): returns application defaults
|
|
90
|
+
- get_plugin_configs(): returns merged plugin configs
|
|
91
|
+
- load_complete_config(): returns full merged config
|
|
92
|
+
- _load_user_config_with_fallback(): local -> global priority
|
|
93
|
+
|
|
94
|
+
config priority order (highest to lowest):
|
|
95
|
+
1. environment variables (kollabor_*)
|
|
96
|
+
2. local config (.kollabor-cli/config.json in cwd)
|
|
97
|
+
3. global config (~/.kollabor-cli/config.json)
|
|
98
|
+
4. plugin-provided defaults
|
|
99
|
+
5. base application defaults
|
|
100
|
+
|
|
101
|
+
plugin config manager (core/config/plugin_config_manager.py)
|
|
102
|
+
- plugin_schemas: registered plugin config schemas
|
|
103
|
+
- widget_definitions: ui widget definitions
|
|
104
|
+
- discover_plugin_schemas(): find plugin get_config_schema() methods
|
|
105
|
+
- validate_plugin_config(): validate config against schema
|
|
106
|
+
- get_plugin_default_config(): get defaults for a plugin
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
phase 1: config file discovery and structure validation
|
|
110
|
+
|
|
111
|
+
step 1: locate active config file
|
|
112
|
+
|
|
113
|
+
check which config is being used:
|
|
114
|
+
<terminal>python -c "
|
|
115
|
+
from pathlib import path
|
|
116
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
117
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
118
|
+
if local.exists():
|
|
119
|
+
print(f'using local: {local}')
|
|
120
|
+
elif global.exists():
|
|
121
|
+
print(f'using global: {global}')
|
|
122
|
+
else:
|
|
123
|
+
print('no config file found - using defaults')
|
|
124
|
+
"</terminal>
|
|
125
|
+
|
|
126
|
+
check for both configs:
|
|
127
|
+
<terminal>ls -la .kollabor-cli/config.json ~/.kollabor-cli/config.json 2>&0</terminal>
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
step 2: validate json syntax
|
|
131
|
+
|
|
132
|
+
validate local config:
|
|
133
|
+
<terminal>python -c "
|
|
134
|
+
import json, sys
|
|
135
|
+
try:
|
|
136
|
+
with open('.kollabor-cli/config.json') as f:
|
|
137
|
+
data = json.load(f)
|
|
138
|
+
print(f'[ok] valid json, {len(data)} top-level keys')
|
|
139
|
+
except json.jsondecodeerror as e:
|
|
140
|
+
print(f'[error] json syntax error: {e}')
|
|
141
|
+
sys.exit(1)
|
|
142
|
+
except filenotfounderror:
|
|
143
|
+
print('[warn] no local config file')
|
|
144
|
+
"</terminal>
|
|
145
|
+
|
|
146
|
+
validate global config:
|
|
147
|
+
<terminal>python -c "
|
|
148
|
+
import json, sys
|
|
149
|
+
from pathlib import path
|
|
150
|
+
p = path.home() / '.kollabor-cli' / 'config.json'
|
|
151
|
+
try:
|
|
152
|
+
with open(p) as f:
|
|
153
|
+
data = json.load(f)
|
|
154
|
+
print(f'[ok] valid json, {len(data)} top-level keys')
|
|
155
|
+
except json.jsondecodeerror as e:
|
|
156
|
+
print(f'[error] json syntax error: {e}')
|
|
157
|
+
except filenotfounderror:
|
|
158
|
+
print('[warn] no global config file')
|
|
159
|
+
"</terminal>
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
step 3: check required top-level sections
|
|
163
|
+
|
|
164
|
+
verify config structure:
|
|
165
|
+
<terminal>python -c "
|
|
166
|
+
import json
|
|
167
|
+
from pathlib import path
|
|
168
|
+
|
|
169
|
+
required_sections = ['terminal', 'input', 'logging', 'core', 'plugins', 'application']
|
|
170
|
+
|
|
171
|
+
config_path = None
|
|
172
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
173
|
+
if local.exists():
|
|
174
|
+
config_path = local
|
|
175
|
+
else:
|
|
176
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
177
|
+
if global.exists():
|
|
178
|
+
config_path = global
|
|
179
|
+
|
|
180
|
+
if not config_path:
|
|
181
|
+
print('[warn] no config file found')
|
|
182
|
+
else:
|
|
183
|
+
with open(config_path) as f:
|
|
184
|
+
config = json.load(f)
|
|
185
|
+
|
|
186
|
+
print('config structure check:')
|
|
187
|
+
for section in required_sections:
|
|
188
|
+
if section in config:
|
|
189
|
+
print(f' [ok] {section}')
|
|
190
|
+
else:
|
|
191
|
+
print(f' [warn] {section} - missing (will use defaults)')
|
|
192
|
+
|
|
193
|
+
# check for extra/unknown sections
|
|
194
|
+
known = required_sections + ['workflow_enforcement', 'performance', 'hooks']
|
|
195
|
+
for key in config.keys():
|
|
196
|
+
if key not in known:
|
|
197
|
+
print(f' [info] {key} - custom section')
|
|
198
|
+
"</terminal>
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
phase 2: setting validation
|
|
202
|
+
|
|
203
|
+
step 1: verify required llm settings
|
|
204
|
+
|
|
205
|
+
check core llm settings:
|
|
206
|
+
<terminal>python -c "
|
|
207
|
+
import json
|
|
208
|
+
from pathlib import path
|
|
209
|
+
|
|
210
|
+
config_path = none
|
|
211
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
212
|
+
if local.exists():
|
|
213
|
+
config_path = local
|
|
214
|
+
else:
|
|
215
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
216
|
+
if global.exists():
|
|
217
|
+
config_path = global
|
|
218
|
+
|
|
219
|
+
# check base defaults from loader
|
|
220
|
+
print('checking llm settings...')
|
|
221
|
+
|
|
222
|
+
required_settings = {
|
|
223
|
+
'core.llm.api_url': 'llm api endpoint url',
|
|
224
|
+
'core.llm.model': 'model name/identifier',
|
|
225
|
+
'core.llm.temperature': 'sampling temperature (0.0-1.0)',
|
|
226
|
+
'core.llm.max_history': 'conversation history limit'
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if config_path:
|
|
230
|
+
with open(config_path) as f:
|
|
231
|
+
config = json.load(f)
|
|
232
|
+
|
|
233
|
+
print('llm settings in config:')
|
|
234
|
+
for key, desc in required_settings.items():
|
|
235
|
+
parts = key.split('.')
|
|
236
|
+
value = config
|
|
237
|
+
try:
|
|
238
|
+
for part in parts:
|
|
239
|
+
value = value[part]
|
|
240
|
+
print(f' [ok] {key}: {value}')
|
|
241
|
+
except (keyerror, typeerror):
|
|
242
|
+
print(f' [info] {key}: using default')
|
|
243
|
+
else:
|
|
244
|
+
print(' no config file - all settings using defaults')
|
|
245
|
+
"</terminal>
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
step 2: validate setting values
|
|
249
|
+
|
|
250
|
+
check for invalid values:
|
|
251
|
+
<terminal>python -c "
|
|
252
|
+
import json
|
|
253
|
+
from pathlib import path
|
|
254
|
+
|
|
255
|
+
def validate_config(config):
|
|
256
|
+
warnings = []
|
|
257
|
+
errors = []
|
|
258
|
+
|
|
259
|
+
# check temperature range
|
|
260
|
+
try:
|
|
261
|
+
temp = config.get('core', {}).get('llm', {}).get('temperature', 0.7)
|
|
262
|
+
if not 0.0 <= temp <= 2.0:
|
|
263
|
+
errors.append(f'invalid temperature: {temp} (must be 0.0-2.0)')
|
|
264
|
+
except: pass
|
|
265
|
+
|
|
266
|
+
# check max_history
|
|
267
|
+
try:
|
|
268
|
+
history = config.get('core', {}).get('llm', {}).get('max_history', 90)
|
|
269
|
+
if history < 0 or history > 1000:
|
|
270
|
+
warnings.append(f'unusual max_history: {history}')
|
|
271
|
+
except: pass
|
|
272
|
+
|
|
273
|
+
# check timeout values
|
|
274
|
+
try:
|
|
275
|
+
timeout = config.get('core', {}).get('llm', {}).get('timeout', 0)
|
|
276
|
+
if timeout < 0:
|
|
277
|
+
errors.append(f'invalid timeout: {timeout} (must be >= 0)')
|
|
278
|
+
except: pass
|
|
279
|
+
|
|
280
|
+
# check render_fps
|
|
281
|
+
try:
|
|
282
|
+
fps = config.get('terminal', {}).get('render_fps', 20)
|
|
283
|
+
if fps < 1 or fps > 120:
|
|
284
|
+
warnings.append(f'unusual render_fps: {fps}')
|
|
285
|
+
except: pass
|
|
286
|
+
|
|
287
|
+
return errors, warnings
|
|
288
|
+
|
|
289
|
+
config_path = none
|
|
290
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
291
|
+
if local.exists():
|
|
292
|
+
config_path = local
|
|
293
|
+
else:
|
|
294
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
295
|
+
if global.exists():
|
|
296
|
+
config_path = global
|
|
297
|
+
|
|
298
|
+
if config_path:
|
|
299
|
+
with open(config_path) as f:
|
|
300
|
+
config = json.load(f)
|
|
301
|
+
errors, warnings = validate_config(config)
|
|
302
|
+
|
|
303
|
+
if errors:
|
|
304
|
+
print('errors:')
|
|
305
|
+
for e in errors:
|
|
306
|
+
print(f' [error] {e}')
|
|
307
|
+
|
|
308
|
+
if warnings:
|
|
309
|
+
print('warnings:')
|
|
310
|
+
for w in warnings:
|
|
311
|
+
print(f' [warn] {w}')
|
|
312
|
+
|
|
313
|
+
if not errors and not warnings:
|
|
314
|
+
print('[ok] all setting values valid')
|
|
315
|
+
else:
|
|
316
|
+
print('[info] no config file - using defaults')
|
|
317
|
+
"</terminal>
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
step 3: validate plugin configurations
|
|
321
|
+
|
|
322
|
+
check plugin configs:
|
|
323
|
+
<terminal>python -c "
|
|
324
|
+
import json
|
|
325
|
+
from pathlib import path
|
|
326
|
+
|
|
327
|
+
config_path = none
|
|
328
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
329
|
+
if local.exists():
|
|
330
|
+
config_path = local
|
|
331
|
+
else:
|
|
332
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
333
|
+
if global.exists():
|
|
334
|
+
config_path = global
|
|
335
|
+
|
|
336
|
+
known_plugins = [
|
|
337
|
+
'enhanced_input', 'system_commands', 'hook_monitoring',
|
|
338
|
+
'query_enhancer', 'workflow_enforcement', 'fullscreen'
|
|
339
|
+
]
|
|
340
|
+
|
|
341
|
+
if config_path:
|
|
342
|
+
with open(config_path) as f:
|
|
343
|
+
config = json.load(f)
|
|
344
|
+
|
|
345
|
+
plugins = config.get('plugins', {})
|
|
346
|
+
print('plugin configurations:')
|
|
347
|
+
|
|
348
|
+
for plugin_name in known_plugins:
|
|
349
|
+
if plugin_name in plugins:
|
|
350
|
+
plugin_config = plugins[plugin_name]
|
|
351
|
+
enabled = plugin_config.get('enabled', false)
|
|
352
|
+
status = '[ok]' if enabled else '[info]'
|
|
353
|
+
print(f' {status} {plugin_name}: enabled={enabled}')
|
|
354
|
+
else:
|
|
355
|
+
print(f' [warn] {plugin_name}: not in config (will use defaults)')
|
|
356
|
+
|
|
357
|
+
# check for unknown plugins
|
|
358
|
+
for plugin_name in plugins.keys():
|
|
359
|
+
if plugin_name not in known_plugins:
|
|
360
|
+
print(f' [info] {plugin_name}: custom/unknown plugin')
|
|
361
|
+
else:
|
|
362
|
+
print('[info] no config file - all plugins using defaults')
|
|
363
|
+
"</terminal>
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
phase 3: conflict detection
|
|
367
|
+
|
|
368
|
+
step 1: check for duplicate settings
|
|
369
|
+
|
|
370
|
+
find settings defined in multiple places:
|
|
371
|
+
<terminal>python -c "
|
|
372
|
+
import json
|
|
373
|
+
from pathlib import path
|
|
374
|
+
|
|
375
|
+
def find_all_configs():
|
|
376
|
+
configs = []
|
|
377
|
+
|
|
378
|
+
# local config
|
|
379
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
380
|
+
if local.exists():
|
|
381
|
+
with open(local) as f:
|
|
382
|
+
configs.append(('local', json.load(f)))
|
|
383
|
+
|
|
384
|
+
# global config
|
|
385
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
386
|
+
if global.exists():
|
|
387
|
+
with open(global) as f:
|
|
388
|
+
configs.append(('global', json.load(f)))
|
|
389
|
+
|
|
390
|
+
return configs
|
|
391
|
+
|
|
392
|
+
def flatten_config(d, prefix=''):
|
|
393
|
+
items = []
|
|
394
|
+
for k, v in d.items():
|
|
395
|
+
key = f'{prefix}.{k}' if prefix else k
|
|
396
|
+
if isinstance(v, dict):
|
|
397
|
+
items.extend(flatten_config(v, key))
|
|
398
|
+
else:
|
|
399
|
+
items.append((key, v))
|
|
400
|
+
return items
|
|
401
|
+
|
|
402
|
+
configs = find_all_configs()
|
|
403
|
+
|
|
404
|
+
if len(configs) <= 1:
|
|
405
|
+
print('[info] only one config source - no conflicts possible')
|
|
406
|
+
else:
|
|
407
|
+
# collect all settings from all configs
|
|
408
|
+
all_settings = {}
|
|
409
|
+
for name, config in configs:
|
|
410
|
+
for key, value in flatten_config(config):
|
|
411
|
+
if key not in all_settings:
|
|
412
|
+
all_settings[key] = []
|
|
413
|
+
all_settings[key].append((name, value))
|
|
414
|
+
|
|
415
|
+
# find duplicates with different values
|
|
416
|
+
print('potential conflicts (same key, different value):')
|
|
417
|
+
conflicts_found = false
|
|
418
|
+
for key, sources in all_settings.items():
|
|
419
|
+
if len(sources) > 1:
|
|
420
|
+
values = set(str(v) for _, v in sources)
|
|
421
|
+
if len(values) > 1:
|
|
422
|
+
conflicts_found = true
|
|
423
|
+
print(f' [warn] {key}:')
|
|
424
|
+
for source, value in sources:
|
|
425
|
+
print(f' {source}: {value}')
|
|
426
|
+
|
|
427
|
+
if not conflicts_found:
|
|
428
|
+
print('[ok] no conflicting values found')
|
|
429
|
+
"</terminal>
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
step 2: check plugin config conflicts
|
|
433
|
+
|
|
434
|
+
check for incompatible plugin combinations:
|
|
435
|
+
<terminal>python -c "
|
|
436
|
+
import json
|
|
437
|
+
from pathlib import path
|
|
438
|
+
|
|
439
|
+
config_path = none
|
|
440
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
441
|
+
if local.exists():
|
|
442
|
+
config_path = local
|
|
443
|
+
else:
|
|
444
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
445
|
+
if global.exists():
|
|
446
|
+
config_path = global
|
|
447
|
+
|
|
448
|
+
# known incompatible combinations
|
|
449
|
+
incompatible_plugins = [
|
|
450
|
+
# workflow_enforcement interferes with normal operation
|
|
451
|
+
('workflow_enforcement', 'query_enhancer'),
|
|
452
|
+
]
|
|
453
|
+
|
|
454
|
+
if config_path:
|
|
455
|
+
with open(config_path) as f:
|
|
456
|
+
config = json.load(f)
|
|
457
|
+
|
|
458
|
+
plugins = config.get('plugins', {})
|
|
459
|
+
enabled = [name for name, cfg in plugins.items() if cfg.get('enabled', false)]
|
|
460
|
+
|
|
461
|
+
print('checking plugin compatibility...')
|
|
462
|
+
for p1, p2 in incompatible_plugins:
|
|
463
|
+
if p1 in enabled and p2 in enabled:
|
|
464
|
+
print(f' [warn] {p1} and {p2} may not work well together')
|
|
465
|
+
|
|
466
|
+
# check for duplicate-like plugins
|
|
467
|
+
input_plugins = [p for p in enabled if 'input' in p.lower()]
|
|
468
|
+
if len(input_plugins) > 1:
|
|
469
|
+
print(f' [warn] multiple input-related plugins: {input_plugins}')
|
|
470
|
+
|
|
471
|
+
print('[ok] plugin compatibility check complete')
|
|
472
|
+
else:
|
|
473
|
+
print('[info] no config file')
|
|
474
|
+
"</terminal>
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
phase 4: effective config analysis
|
|
478
|
+
|
|
479
|
+
step 1: show merged configuration structure
|
|
480
|
+
|
|
481
|
+
display effective config:
|
|
482
|
+
<terminal>python -c "
|
|
483
|
+
import sys
|
|
484
|
+
sys.path.insert(0, '.')
|
|
485
|
+
|
|
486
|
+
from core.config.loader import configloader
|
|
487
|
+
from core.config.manager import configmanager
|
|
488
|
+
from pathlib import path
|
|
489
|
+
|
|
490
|
+
# create config loader
|
|
491
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
492
|
+
manager = configmanager(local)
|
|
493
|
+
loader = configloader(manager)
|
|
494
|
+
|
|
495
|
+
# get complete merged config
|
|
496
|
+
config = loader.load_complete_config()
|
|
497
|
+
|
|
498
|
+
print('effective configuration (merged):')
|
|
499
|
+
print('=' * 50)
|
|
500
|
+
|
|
501
|
+
# show top-level keys
|
|
502
|
+
for key in sorted(config.keys()):
|
|
503
|
+
value = config[key]
|
|
504
|
+
if isinstance(value, dict):
|
|
505
|
+
print(f'{key}:')
|
|
506
|
+
for subkey in sorted(value.keys())[:5]: # show first 5
|
|
507
|
+
print(f' - {subkey}')
|
|
508
|
+
if len(value) > 5:
|
|
509
|
+
print(f' ... and {len(value) - 5} more')
|
|
510
|
+
else:
|
|
511
|
+
print(f'{key}: {value}')
|
|
512
|
+
"</terminal>
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
step 2: trace setting sources
|
|
516
|
+
|
|
517
|
+
find where a setting comes from:
|
|
518
|
+
<terminal>python -c "
|
|
519
|
+
import sys
|
|
520
|
+
sys.path.insert(0, '.')
|
|
521
|
+
|
|
522
|
+
from core.config.loader import configloader
|
|
523
|
+
from core.config.manager import configmanager
|
|
524
|
+
from pathlib import path
|
|
525
|
+
import json
|
|
526
|
+
|
|
527
|
+
# check each layer
|
|
528
|
+
def get_setting_path(config_dict, path_parts):
|
|
529
|
+
value = config_dict
|
|
530
|
+
for part in path_parts:
|
|
531
|
+
if isinstance(value, dict) and part in value:
|
|
532
|
+
value = value[part]
|
|
533
|
+
else:
|
|
534
|
+
return none
|
|
535
|
+
return value
|
|
536
|
+
|
|
537
|
+
setting = 'core.llm.api_url' # change this to check different settings
|
|
538
|
+
parts = setting.split('.')
|
|
539
|
+
|
|
540
|
+
print(f'tracing setting: {setting}')
|
|
541
|
+
print('-' * 40)
|
|
542
|
+
|
|
543
|
+
# check base defaults
|
|
544
|
+
print('[1] base defaults:')
|
|
545
|
+
loader_instance = configloader(configmanager(path.cwd() / '.kollabor-cli' / 'config.json'))
|
|
546
|
+
base = loader_instance.get_base_config()
|
|
547
|
+
value = get_setting_path(base, parts)
|
|
548
|
+
if value is not none:
|
|
549
|
+
print(f' value: {value}')
|
|
550
|
+
|
|
551
|
+
# check user config
|
|
552
|
+
print('[2] user config:')
|
|
553
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
554
|
+
if local.exists():
|
|
555
|
+
with open(local) as f:
|
|
556
|
+
user = json.load(f)
|
|
557
|
+
value = get_setting_path(user, parts)
|
|
558
|
+
if value is not none:
|
|
559
|
+
print(f' value: {value}')
|
|
560
|
+
print(f' source: {local}')
|
|
561
|
+
else:
|
|
562
|
+
print(' no local config')
|
|
563
|
+
|
|
564
|
+
# final effective value
|
|
565
|
+
print('[3] effective value:')
|
|
566
|
+
effective = loader_instance.load_complete_config()
|
|
567
|
+
value = get_setting_path(effective, parts)
|
|
568
|
+
if value is not none:
|
|
569
|
+
print(f' {value}')
|
|
570
|
+
"</terminal>
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
step 3: compare config to defaults
|
|
574
|
+
|
|
575
|
+
show user overrides:
|
|
576
|
+
<terminal>python -c "
|
|
577
|
+
import sys
|
|
578
|
+
sys.path.insert(0, '.')
|
|
579
|
+
|
|
580
|
+
from core.config.loader import configloader
|
|
581
|
+
from core.config.manager import configmanager
|
|
582
|
+
from pathlib import path
|
|
583
|
+
import json
|
|
584
|
+
|
|
585
|
+
def compare_configs(default, user):
|
|
586
|
+
differences = []
|
|
587
|
+
|
|
588
|
+
def flatten(d, prefix=''):
|
|
589
|
+
items = {}
|
|
590
|
+
for k, v in d.items():
|
|
591
|
+
key = f'{prefix}.{k}' if prefix else k
|
|
592
|
+
if isinstance(v, dict):
|
|
593
|
+
items.update(flatten(v, key))
|
|
594
|
+
else:
|
|
595
|
+
items[key] = v
|
|
596
|
+
return items
|
|
597
|
+
|
|
598
|
+
flat_default = flatten(default)
|
|
599
|
+
flat_user = flatten(user)
|
|
600
|
+
|
|
601
|
+
# find overrides
|
|
602
|
+
for key in flat_user:
|
|
603
|
+
if key in flat_default:
|
|
604
|
+
if flat_default[key] != flat_user[key]:
|
|
605
|
+
differences.append({
|
|
606
|
+
'key': key,
|
|
607
|
+
'default': flat_default[key],
|
|
608
|
+
'user': flat_user[key]
|
|
609
|
+
})
|
|
610
|
+
else:
|
|
611
|
+
differences.append({
|
|
612
|
+
'key': key,
|
|
613
|
+
'default': '(not set)',
|
|
614
|
+
'user': flat_user[key]
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
return differences
|
|
618
|
+
|
|
619
|
+
print('user overrides vs defaults:')
|
|
620
|
+
print('=' * 50)
|
|
621
|
+
|
|
622
|
+
loader = configloader(configmanager(path.cwd() / '.kollabor-cli' / 'config.json'))
|
|
623
|
+
default = loader.get_base_config()
|
|
624
|
+
|
|
625
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
626
|
+
if local.exists():
|
|
627
|
+
with open(local) as f:
|
|
628
|
+
user = json.load(f)
|
|
629
|
+
|
|
630
|
+
diffs = compare_configs(default, user)
|
|
631
|
+
|
|
632
|
+
if diffs:
|
|
633
|
+
for diff in diffs[:20]: # show first 20
|
|
634
|
+
print(f"{diff['key']}:")
|
|
635
|
+
print(f" default: {diff['default']}")
|
|
636
|
+
print(f" user: {diff['user']}")
|
|
637
|
+
|
|
638
|
+
if len(diffs) > 20:
|
|
639
|
+
print(f'... and {len(diffs) - 20} more differences')
|
|
640
|
+
else:
|
|
641
|
+
print('[ok] config matches defaults')
|
|
642
|
+
else:
|
|
643
|
+
print('[info] no local config file')
|
|
644
|
+
"</terminal>
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
example workflow:
|
|
648
|
+
|
|
649
|
+
scenario: "kollabor not connecting to llm"
|
|
650
|
+
|
|
651
|
+
step 1: check config file exists
|
|
652
|
+
<terminal>ls -la .kollabor-cli/config.json ~/.kollabor-cli/config.json</terminal>
|
|
653
|
+
|
|
654
|
+
step 2: verify llm settings in config
|
|
655
|
+
<terminal>python -c "
|
|
656
|
+
import json
|
|
657
|
+
from pathlib import path
|
|
658
|
+
|
|
659
|
+
for p in [path.cwd() / '.kollabor-cli' / 'config.json', path.home() / '.kollabor-cli' / 'config.json']:
|
|
660
|
+
if p.exists():
|
|
661
|
+
with open(p) as f:
|
|
662
|
+
cfg = json.load(f)
|
|
663
|
+
llm = cfg.get('core', {}).get('llm', {})
|
|
664
|
+
print(f'file: {p}')
|
|
665
|
+
print(f' api_url: {llm.get(\"api_url\", \"(default)\")}')
|
|
666
|
+
print(f' model: {llm.get(\"model\", \"(default)\")}')
|
|
667
|
+
print(f' api_token: {\"(set)\" if llm.get(\"api_token\") else \"(empty)\"}')
|
|
668
|
+
print()
|
|
669
|
+
"</terminal>
|
|
670
|
+
|
|
671
|
+
step 3: check for syntax errors
|
|
672
|
+
<terminal>python -c "import json; json.load(open('.kollabor-cli/config.json'))"</terminal>
|
|
673
|
+
|
|
674
|
+
step 4: verify effective config
|
|
675
|
+
<terminal>python -c "
|
|
676
|
+
import sys
|
|
677
|
+
sys.path.insert(0, '.')
|
|
678
|
+
from core.config.loader import configloader
|
|
679
|
+
from core.config.manager import configmanager
|
|
680
|
+
from pathlib import path
|
|
681
|
+
|
|
682
|
+
loader = configloader(configmanager(path.cwd() / '.kollabor-cli' / 'config.json'))
|
|
683
|
+
cfg = loader.load_complete_config()
|
|
684
|
+
print('effective api_url:', cfg['core']['llm']['api_url'])
|
|
685
|
+
"</terminal>
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
example workflow 2:
|
|
689
|
+
|
|
690
|
+
scenario: "plugin configuration not taking effect"
|
|
691
|
+
|
|
692
|
+
step 1: check plugin in config
|
|
693
|
+
<terminal>grep -a 10 '"enhanced_input"' .kollabor-cli/config.json</terminal>
|
|
694
|
+
|
|
695
|
+
step 2: verify enabled status
|
|
696
|
+
<terminal>python -c "
|
|
697
|
+
import json
|
|
698
|
+
with open('.kollabor-cli/config.json') as f:
|
|
699
|
+
cfg = json.load(f)
|
|
700
|
+
print('enhanced_input enabled:', cfg.get('plugins', {}).get('enhanced_input', {}).get('enabled', false))
|
|
701
|
+
"</terminal>
|
|
702
|
+
|
|
703
|
+
step 3: check for plugin config errors in logs
|
|
704
|
+
<terminal>grep -i "plugin.*error\|plugin.*fail" .kollabor-cli/logs/kollabor.log | tail -20</terminal>
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
troubleshooting tips:
|
|
708
|
+
|
|
709
|
+
tip 1: config changes not taking effect
|
|
710
|
+
- verify editing correct config file (check local vs global)
|
|
711
|
+
- json syntax errors will cause silent fallback to defaults
|
|
712
|
+
- some settings require application restart
|
|
713
|
+
- check logs for config loading errors
|
|
714
|
+
|
|
715
|
+
tip 2: missing expected settings
|
|
716
|
+
- not all settings need to be in config.json
|
|
717
|
+
- defaults come from core/config/loader.py:get_base_config()
|
|
718
|
+
- plugins can provide defaults via get_config_schema()
|
|
719
|
+
- check logs for "using default" messages
|
|
720
|
+
|
|
721
|
+
tip 3: plugin configuration issues
|
|
722
|
+
- plugins must be registered in plugins section
|
|
723
|
+
- each plugin needs "enabled" boolean
|
|
724
|
+
- plugin configs merge with defaults, don't need all keys
|
|
725
|
+
- check plugin's get_default_config() for expected structure
|
|
726
|
+
|
|
727
|
+
tip 4: understanding priority
|
|
728
|
+
- local (.kollabor-cli/config.json) overrides global (~/.kollabor-cli/config.json)
|
|
729
|
+
- user config overrides plugin defaults
|
|
730
|
+
- plugin defaults override base defaults
|
|
731
|
+
- env vars (kollabor_*) override everything
|
|
732
|
+
|
|
733
|
+
tip 5: debugging config loading
|
|
734
|
+
- set log level to debug: "logging": {"level": "debug"}
|
|
735
|
+
- check logs for "loaded config" messages
|
|
736
|
+
- look for "merged configuration" entries
|
|
737
|
+
- errors during config load fall back to defaults silently
|
|
738
|
+
|
|
739
|
+
tip 6: common config mistakes
|
|
740
|
+
- trailing comma in json (invalid syntax)
|
|
741
|
+
- using single quotes instead of double quotes
|
|
742
|
+
- missing closing brace }
|
|
743
|
+
- wrong data type (string instead of number)
|
|
744
|
+
- incorrect nested structure (core.llm vs core:llm)
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
expected output:
|
|
748
|
+
|
|
749
|
+
when this skill executes successfully, you should be able to:
|
|
750
|
+
|
|
751
|
+
[ ] locate and identify active config file
|
|
752
|
+
[ ] validate json syntax of config files
|
|
753
|
+
[ ] verify required settings are present
|
|
754
|
+
[ ] detect conflicting configuration values
|
|
755
|
+
[ ] understand effective vs default configuration
|
|
756
|
+
[ ] trace where each setting comes from
|
|
757
|
+
[ ] identify user overrides vs defaults
|
|
758
|
+
[ ] diagnose plugin configuration issues
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
quick validation commands:
|
|
762
|
+
|
|
763
|
+
basic health check:
|
|
764
|
+
<terminal>python -c "
|
|
765
|
+
import sys, json
|
|
766
|
+
from pathlib import path
|
|
767
|
+
|
|
768
|
+
checks = []
|
|
769
|
+
|
|
770
|
+
# check local config
|
|
771
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
772
|
+
if local.exists():
|
|
773
|
+
try:
|
|
774
|
+
with open(local) as f:
|
|
775
|
+
json.load(f)
|
|
776
|
+
checks.append(('[ok]', 'local config exists and valid'))
|
|
777
|
+
except json.jsondecodeerror as e:
|
|
778
|
+
checks.append(('[error]', f'local config has invalid json: {e}'))
|
|
779
|
+
except exception as e:
|
|
780
|
+
checks.append(('[error]', f'local config error: {e}'))
|
|
781
|
+
else:
|
|
782
|
+
checks.append(('[info]', 'no local config'))
|
|
783
|
+
|
|
784
|
+
# check global config
|
|
785
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
786
|
+
if global.exists():
|
|
787
|
+
try:
|
|
788
|
+
with open(global) as f:
|
|
789
|
+
json.load(f)
|
|
790
|
+
checks.append(('[ok]', 'global config exists and valid'))
|
|
791
|
+
except json.jsondecodeerror as e:
|
|
792
|
+
checks.append(('[error]', f'global config has invalid json: {e}'))
|
|
793
|
+
except exception as e:
|
|
794
|
+
checks.append(('[error]', f'global config error: {e}'))
|
|
795
|
+
else:
|
|
796
|
+
checks.append(('[info]', 'no global config'))
|
|
797
|
+
|
|
798
|
+
# print results
|
|
799
|
+
for status, msg in checks:
|
|
800
|
+
print(f'{status} {msg}')
|
|
801
|
+
"</terminal>
|
|
802
|
+
|
|
803
|
+
full validation report:
|
|
804
|
+
<terminal>python -c "
|
|
805
|
+
import sys
|
|
806
|
+
sys.path.insert(0, '.')
|
|
807
|
+
from pathlib import path
|
|
808
|
+
import json
|
|
809
|
+
|
|
810
|
+
print('=' * 60)
|
|
811
|
+
print('kollabor configuration validation report')
|
|
812
|
+
print('=' * 60)
|
|
813
|
+
|
|
814
|
+
# check config files
|
|
815
|
+
local = path.cwd() / '.kollabor-cli' / 'config.json'
|
|
816
|
+
global = path.home() / '.kollabor-cli' / 'config.json'
|
|
817
|
+
|
|
818
|
+
print('\n[1] config files:')
|
|
819
|
+
if local.exists():
|
|
820
|
+
print(' [ok] local config: .kollabor-cli/config.json')
|
|
821
|
+
else:
|
|
822
|
+
print(' [info] no local config')
|
|
823
|
+
|
|
824
|
+
if global.exists():
|
|
825
|
+
print(' [ok] global config: ~/.kollabor-cli/config.json')
|
|
826
|
+
else:
|
|
827
|
+
print(' [info] no global config')
|
|
828
|
+
|
|
829
|
+
# validate syntax
|
|
830
|
+
print('\n[2] json syntax:')
|
|
831
|
+
for name, path in [('local', local), ('global', global)]:
|
|
832
|
+
if path.exists():
|
|
833
|
+
try:
|
|
834
|
+
with open(path) as f:
|
|
835
|
+
data = json.load(f)
|
|
836
|
+
print(f' [ok] {name}: valid json')
|
|
837
|
+
except json.jsondecodeerror as e:
|
|
838
|
+
print(f' [error] {name}: {e}')
|
|
839
|
+
|
|
840
|
+
# check structure
|
|
841
|
+
print('\n[3] config structure:')
|
|
842
|
+
config_path = local if local.exists() else (global if global.exists() else none)
|
|
843
|
+
if config_path:
|
|
844
|
+
with open(config_path) as f:
|
|
845
|
+
config = json.load(f)
|
|
846
|
+
|
|
847
|
+
required = ['terminal', 'input', 'logging', 'core', 'plugins']
|
|
848
|
+
for section in required:
|
|
849
|
+
if section in config:
|
|
850
|
+
print(f' [ok] {section}')
|
|
851
|
+
else:
|
|
852
|
+
print(f' [warn] {section}: missing (defaults used)')
|
|
853
|
+
|
|
854
|
+
print('\n[4] summary:')
|
|
855
|
+
if local.exists() or global.exists():
|
|
856
|
+
print(' [ok] configuration file(s) found')
|
|
857
|
+
print(' run specific validation phases for detailed analysis')
|
|
858
|
+
else:
|
|
859
|
+
print(' [info] no config files - using application defaults')
|
|
860
|
+
print(' config is optional, defaults will be used')
|
|
861
|
+
|
|
862
|
+
print('\n' + '=' * 60)
|
|
863
|
+
"</terminal>
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
status tags reference:
|
|
867
|
+
|
|
868
|
+
[ok] configuration is valid
|
|
869
|
+
[warn] potential issue that should be reviewed
|
|
870
|
+
[error] definite problem that needs fixing
|
|
871
|
+
[info] informational message
|
|
872
|
+
[todo] action required
|
|
873
|
+
|
|
874
|
+
common exit conditions:
|
|
875
|
+
|
|
876
|
+
[ok] all validations passed
|
|
877
|
+
[ok] issues identified and resolved
|
|
878
|
+
[warn] non-critical issues found
|
|
879
|
+
[error] critical configuration errors found
|