kollabor 0.4.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core/__init__.py +18 -0
- core/application.py +578 -0
- core/cli.py +193 -0
- core/commands/__init__.py +43 -0
- core/commands/executor.py +277 -0
- core/commands/menu_renderer.py +319 -0
- core/commands/parser.py +186 -0
- core/commands/registry.py +331 -0
- core/commands/system_commands.py +479 -0
- core/config/__init__.py +7 -0
- core/config/llm_task_config.py +110 -0
- core/config/loader.py +501 -0
- core/config/manager.py +112 -0
- core/config/plugin_config_manager.py +346 -0
- core/config/plugin_schema.py +424 -0
- core/config/service.py +399 -0
- core/effects/__init__.py +1 -0
- core/events/__init__.py +12 -0
- core/events/bus.py +129 -0
- core/events/executor.py +154 -0
- core/events/models.py +258 -0
- core/events/processor.py +176 -0
- core/events/registry.py +289 -0
- core/fullscreen/__init__.py +19 -0
- core/fullscreen/command_integration.py +290 -0
- core/fullscreen/components/__init__.py +12 -0
- core/fullscreen/components/animation.py +258 -0
- core/fullscreen/components/drawing.py +160 -0
- core/fullscreen/components/matrix_components.py +177 -0
- core/fullscreen/manager.py +302 -0
- core/fullscreen/plugin.py +204 -0
- core/fullscreen/renderer.py +282 -0
- core/fullscreen/session.py +324 -0
- core/io/__init__.py +52 -0
- core/io/buffer_manager.py +362 -0
- core/io/config_status_view.py +272 -0
- core/io/core_status_views.py +410 -0
- core/io/input_errors.py +313 -0
- core/io/input_handler.py +2655 -0
- core/io/input_mode_manager.py +402 -0
- core/io/key_parser.py +344 -0
- core/io/layout.py +587 -0
- core/io/message_coordinator.py +204 -0
- core/io/message_renderer.py +601 -0
- core/io/modal_interaction_handler.py +315 -0
- core/io/raw_input_processor.py +946 -0
- core/io/status_renderer.py +845 -0
- core/io/terminal_renderer.py +586 -0
- core/io/terminal_state.py +551 -0
- core/io/visual_effects.py +734 -0
- core/llm/__init__.py +26 -0
- core/llm/api_communication_service.py +863 -0
- core/llm/conversation_logger.py +473 -0
- core/llm/conversation_manager.py +414 -0
- core/llm/file_operations_executor.py +1401 -0
- core/llm/hook_system.py +402 -0
- core/llm/llm_service.py +1629 -0
- core/llm/mcp_integration.py +386 -0
- core/llm/message_display_service.py +450 -0
- core/llm/model_router.py +214 -0
- core/llm/plugin_sdk.py +396 -0
- core/llm/response_parser.py +848 -0
- core/llm/response_processor.py +364 -0
- core/llm/tool_executor.py +520 -0
- core/logging/__init__.py +19 -0
- core/logging/setup.py +208 -0
- core/models/__init__.py +5 -0
- core/models/base.py +23 -0
- core/plugins/__init__.py +13 -0
- core/plugins/collector.py +212 -0
- core/plugins/discovery.py +386 -0
- core/plugins/factory.py +263 -0
- core/plugins/registry.py +152 -0
- core/storage/__init__.py +5 -0
- core/storage/state_manager.py +84 -0
- core/ui/__init__.py +6 -0
- core/ui/config_merger.py +176 -0
- core/ui/config_widgets.py +369 -0
- core/ui/live_modal_renderer.py +276 -0
- core/ui/modal_actions.py +162 -0
- core/ui/modal_overlay_renderer.py +373 -0
- core/ui/modal_renderer.py +591 -0
- core/ui/modal_state_manager.py +443 -0
- core/ui/widget_integration.py +222 -0
- core/ui/widgets/__init__.py +27 -0
- core/ui/widgets/base_widget.py +136 -0
- core/ui/widgets/checkbox.py +85 -0
- core/ui/widgets/dropdown.py +140 -0
- core/ui/widgets/label.py +78 -0
- core/ui/widgets/slider.py +185 -0
- core/ui/widgets/text_input.py +224 -0
- core/utils/__init__.py +11 -0
- core/utils/config_utils.py +656 -0
- core/utils/dict_utils.py +212 -0
- core/utils/error_utils.py +275 -0
- core/utils/key_reader.py +171 -0
- core/utils/plugin_utils.py +267 -0
- core/utils/prompt_renderer.py +151 -0
- kollabor-0.4.9.dist-info/METADATA +298 -0
- kollabor-0.4.9.dist-info/RECORD +128 -0
- kollabor-0.4.9.dist-info/WHEEL +5 -0
- kollabor-0.4.9.dist-info/entry_points.txt +2 -0
- kollabor-0.4.9.dist-info/licenses/LICENSE +21 -0
- kollabor-0.4.9.dist-info/top_level.txt +4 -0
- kollabor_cli_main.py +20 -0
- plugins/__init__.py +1 -0
- plugins/enhanced_input/__init__.py +18 -0
- plugins/enhanced_input/box_renderer.py +103 -0
- plugins/enhanced_input/box_styles.py +142 -0
- plugins/enhanced_input/color_engine.py +165 -0
- plugins/enhanced_input/config.py +150 -0
- plugins/enhanced_input/cursor_manager.py +72 -0
- plugins/enhanced_input/geometry.py +81 -0
- plugins/enhanced_input/state.py +130 -0
- plugins/enhanced_input/text_processor.py +115 -0
- plugins/enhanced_input_plugin.py +385 -0
- plugins/fullscreen/__init__.py +9 -0
- plugins/fullscreen/example_plugin.py +327 -0
- plugins/fullscreen/matrix_plugin.py +132 -0
- plugins/hook_monitoring_plugin.py +1299 -0
- plugins/query_enhancer_plugin.py +350 -0
- plugins/save_conversation_plugin.py +502 -0
- plugins/system_commands_plugin.py +93 -0
- plugins/tmux_plugin.py +795 -0
- plugins/workflow_enforcement_plugin.py +629 -0
- system_prompt/default.md +1286 -0
- system_prompt/default_win.md +265 -0
- system_prompt/example_with_trender.md +47 -0
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
"""Visual effects system for terminal rendering."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import List, Tuple, Dict, Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EffectType(Enum):
|
|
10
|
+
"""Types of visual effects."""
|
|
11
|
+
|
|
12
|
+
GRADIENT = "gradient"
|
|
13
|
+
SHIMMER = "shimmer"
|
|
14
|
+
DIM = "dim"
|
|
15
|
+
ANIMATION = "animation"
|
|
16
|
+
COLOR = "color"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class EffectConfig:
|
|
21
|
+
"""Configuration for visual effects."""
|
|
22
|
+
|
|
23
|
+
effect_type: EffectType
|
|
24
|
+
enabled: bool = True
|
|
25
|
+
intensity: float = 1.0
|
|
26
|
+
speed: int = 3
|
|
27
|
+
width: int = 4
|
|
28
|
+
colors: List[str] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ColorPalette:
|
|
32
|
+
"""Color palette definitions for various effects - RGB True Color (24-bit)."""
|
|
33
|
+
|
|
34
|
+
# Standard colors
|
|
35
|
+
RESET = "\033[0m"
|
|
36
|
+
DIM = "\033[2m"
|
|
37
|
+
BRIGHT = "\033[1m"
|
|
38
|
+
|
|
39
|
+
# Basic colors - RGB True Color
|
|
40
|
+
WHITE = "\033[38;2;220;220;220m" # rgb(220, 220, 220)
|
|
41
|
+
BRIGHT_WHITE = "\033[1m\033[38;2;255;255;255m" # Bold + rgb(255, 255, 255)
|
|
42
|
+
BLACK = "\033[38;2;0;0;0m" # rgb(0, 0, 0)
|
|
43
|
+
|
|
44
|
+
# Red variants - RGB True Color
|
|
45
|
+
DIM_RED = "\033[2m\033[38;2;205;49;49m" # Dim + rgb(205, 49, 49)
|
|
46
|
+
RED = "\033[38;2;205;49;49m" # rgb(205, 49, 49)
|
|
47
|
+
BRIGHT_RED = "\033[1m\033[38;2;241;76;76m" # Bold + rgb(241, 76, 76)
|
|
48
|
+
|
|
49
|
+
# Green variants - RGB True Color
|
|
50
|
+
DIM_GREEN = "\033[2m\033[38;2;13;188;121m" # Dim + rgb(13, 188, 121)
|
|
51
|
+
GREEN = "\033[38;2;13;188;121m" # rgb(13, 188, 121)
|
|
52
|
+
BRIGHT_GREEN = "\033[1m\033[38;2;35;209;139m" # Bold + rgb(35, 209, 139)
|
|
53
|
+
|
|
54
|
+
# Yellow variants - RGB True Color
|
|
55
|
+
DIM_YELLOW = "\033[2m\033[38;2;229;192;123m" # Dim + rgb(229, 192, 123)
|
|
56
|
+
YELLOW = "\033[38;2;229;192;123m" # rgb(229, 192, 123)
|
|
57
|
+
BRIGHT_YELLOW = "\033[1m\033[38;2;245;223;77m" # Bold + rgb(245, 223, 77)
|
|
58
|
+
|
|
59
|
+
# Blue variants - RGB True Color
|
|
60
|
+
DIM_BLUE = "\033[2m\033[38;2;36;114;200m" # Dim + rgb(36, 114, 200)
|
|
61
|
+
BLUE = "\033[38;2;36;114;200m" # rgb(36, 114, 200)
|
|
62
|
+
BRIGHT_BLUE = "\033[1m\033[38;2;59;142;234m" # Bold + rgb(59, 142, 234)
|
|
63
|
+
NORMAL_BLUE = "\033[38;2;100;149;237m" # rgb(100, 149, 237) - cornflower blue
|
|
64
|
+
|
|
65
|
+
# Magenta variants - RGB True Color
|
|
66
|
+
DIM_MAGENTA = "\033[2m\033[38;2;188;63;188m" # Dim + rgb(188, 63, 188)
|
|
67
|
+
MAGENTA = "\033[38;2;188;63;188m" # rgb(188, 63, 188)
|
|
68
|
+
BRIGHT_MAGENTA = "\033[1m\033[38;2;214;112;214m" # Bold + rgb(214, 112, 214)
|
|
69
|
+
|
|
70
|
+
# Cyan variants - RGB True Color
|
|
71
|
+
DIM_CYAN = "\033[2m\033[38;2;17;168;205m" # Dim + rgb(17, 168, 205)
|
|
72
|
+
CYAN = "\033[38;2;17;168;205m" # rgb(17, 168, 205)
|
|
73
|
+
BRIGHT_CYAN = "\033[1m\033[38;2;41;184;219m" # Bold + rgb(41, 184, 219)
|
|
74
|
+
|
|
75
|
+
# Grey variants - RGB True Color
|
|
76
|
+
DIM_GREY = "\033[2m\033[38;2;128;128;128m" # Dim + rgb(128, 128, 128)
|
|
77
|
+
GREY = "\033[38;2;128;128;128m" # rgb(128, 128, 128)
|
|
78
|
+
BRIGHT_GREY = "\033[1m\033[38;2;169;169;169m" # Bold + rgb(169, 169, 169)
|
|
79
|
+
|
|
80
|
+
# Extended bright colors - RGB True Color (brighter versions)
|
|
81
|
+
BRIGHT_CYAN_256 = "\033[1m\033[38;2;0;255;255m" # Bold + rgb(0, 255, 255)
|
|
82
|
+
BRIGHT_BLUE_256 = "\033[1m\033[38;2;94;156;255m" # Bold + rgb(94, 156, 255)
|
|
83
|
+
BRIGHT_GREEN_256 = "\033[1m\033[38;2;90;247;142m" # Bold + rgb(90, 247, 142)
|
|
84
|
+
BRIGHT_YELLOW_256 = "\033[1m\033[38;2;255;231;76m" # Bold + rgb(255, 231, 76)
|
|
85
|
+
BRIGHT_MAGENTA_256 = "\033[1m\033[38;2;255;92;205m" # Bold + rgb(255, 92, 205)
|
|
86
|
+
BRIGHT_RED_256 = "\033[1m\033[38;2;255;85;85m" # Bold + rgb(255, 85, 85)
|
|
87
|
+
|
|
88
|
+
# Neon Minimal Palette - RGB True Color (24-bit)
|
|
89
|
+
# Primary: Lime Green #a3e635
|
|
90
|
+
LIME = "\033[38;2;163;230;53m"
|
|
91
|
+
LIME_LIGHT = "\033[38;2;190;242;100m"
|
|
92
|
+
LIME_DARK = "\033[38;2;132;204;22m"
|
|
93
|
+
|
|
94
|
+
# Info: Cyan #06b6d4
|
|
95
|
+
INFO_CYAN = "\033[38;2;6;182;212m"
|
|
96
|
+
INFO_CYAN_LIGHT = "\033[38;2;34;211;238m"
|
|
97
|
+
INFO_CYAN_DARK = "\033[38;2;8;145;178m"
|
|
98
|
+
|
|
99
|
+
# Warning: Gold #eab308
|
|
100
|
+
WARNING_GOLD = "\033[38;2;234;179;8m"
|
|
101
|
+
WARNING_GOLD_LIGHT = "\033[38;2;253;224;71m"
|
|
102
|
+
WARNING_GOLD_DARK = "\033[38;2;202;138;4m"
|
|
103
|
+
|
|
104
|
+
# Error: Bright Red #ef4444
|
|
105
|
+
ERROR_RED = "\033[38;2;239;68;68m"
|
|
106
|
+
ERROR_RED_LIGHT = "\033[38;2;248;113;113m"
|
|
107
|
+
ERROR_RED_DARK = "\033[38;2;220;38;38m"
|
|
108
|
+
|
|
109
|
+
# Muted: Steel #71717a
|
|
110
|
+
MUTED_STEEL = "\033[38;2;113;113;122m"
|
|
111
|
+
DIM_STEEL = "\033[2;38;2;113;113;122m"
|
|
112
|
+
|
|
113
|
+
# Grey gradient levels (256-color palette)
|
|
114
|
+
GREY_LEVELS = [255, 254, 253, 252, 251, 250]
|
|
115
|
+
|
|
116
|
+
# Dim white gradient levels (bright white to subtle dim white)
|
|
117
|
+
DIM_WHITE_LEVELS = [255, 254, 253, 252, 251, 250]
|
|
118
|
+
|
|
119
|
+
# Lime green gradient scheme RGB values for ultra-smooth gradients
|
|
120
|
+
DIM_SCHEME_COLORS = [
|
|
121
|
+
(190, 242, 100), # Bright lime (#bef264)
|
|
122
|
+
(175, 235, 80), # Light lime
|
|
123
|
+
(163, 230, 53), # Primary lime (#a3e635) - hero color!
|
|
124
|
+
(145, 210, 45), # Medium lime
|
|
125
|
+
(132, 204, 22), # Darker lime (#84cc16)
|
|
126
|
+
(115, 180, 18), # Deep lime
|
|
127
|
+
(100, 160, 15), # Strong lime
|
|
128
|
+
(115, 180, 18), # Deep lime (return)
|
|
129
|
+
(132, 204, 22), # Darker lime (return)
|
|
130
|
+
(163, 230, 53), # Primary lime (return)
|
|
131
|
+
(190, 242, 100), # Bright lime
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class GradientRenderer:
|
|
136
|
+
"""Handles various gradient effects."""
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def apply_white_to_grey(text: str) -> str:
|
|
140
|
+
"""Apply smooth white-to-grey gradient effect.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
text: Text to apply gradient to.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Text with gradient effect applied.
|
|
147
|
+
"""
|
|
148
|
+
if not text or "\033[" in text:
|
|
149
|
+
return text
|
|
150
|
+
|
|
151
|
+
result = []
|
|
152
|
+
text_length = len(text)
|
|
153
|
+
grey_levels = ColorPalette.GREY_LEVELS
|
|
154
|
+
|
|
155
|
+
for i, char in enumerate(text):
|
|
156
|
+
# Calculate position in gradient (0.0 to 1.0)
|
|
157
|
+
position = i / max(1, text_length - 1)
|
|
158
|
+
|
|
159
|
+
# Map to grey level with smooth interpolation
|
|
160
|
+
level_index = position * (len(grey_levels) - 1)
|
|
161
|
+
level_index = min(int(level_index), len(grey_levels) - 1)
|
|
162
|
+
|
|
163
|
+
grey_level = grey_levels[level_index]
|
|
164
|
+
color_code = f"\033[38;5;{grey_level}m"
|
|
165
|
+
result.append(f"{color_code}{char}")
|
|
166
|
+
|
|
167
|
+
result.append(ColorPalette.RESET)
|
|
168
|
+
return "".join(result)
|
|
169
|
+
|
|
170
|
+
@staticmethod
|
|
171
|
+
def apply_dim_white_gradient(text: str) -> str:
|
|
172
|
+
"""Apply subtle dim white to dimmer white gradient.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
text: Text to apply gradient to.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Text with dim white gradient applied.
|
|
179
|
+
"""
|
|
180
|
+
if not text or "\033[" in text:
|
|
181
|
+
return text
|
|
182
|
+
|
|
183
|
+
result = []
|
|
184
|
+
text_length = len(text)
|
|
185
|
+
dim_levels = ColorPalette.DIM_WHITE_LEVELS
|
|
186
|
+
|
|
187
|
+
for i, char in enumerate(text):
|
|
188
|
+
# Calculate position in gradient (0.0 to 1.0)
|
|
189
|
+
position = i / max(1, text_length - 1)
|
|
190
|
+
|
|
191
|
+
# Map to dim white level with smooth interpolation
|
|
192
|
+
level_index = position * (len(dim_levels) - 1)
|
|
193
|
+
level_index = min(int(level_index), len(dim_levels) - 1)
|
|
194
|
+
|
|
195
|
+
dim_level = dim_levels[level_index]
|
|
196
|
+
color_code = f"\033[38;5;{dim_level}m"
|
|
197
|
+
result.append(f"{color_code}{char}")
|
|
198
|
+
|
|
199
|
+
result.append(ColorPalette.RESET)
|
|
200
|
+
return "".join(result)
|
|
201
|
+
|
|
202
|
+
@staticmethod
|
|
203
|
+
def apply_dim_scheme_gradient(text: str) -> str:
|
|
204
|
+
"""Apply ultra-smooth gradient using dim color scheme.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
text: Text to apply gradient to.
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Text with dim scheme gradient applied.
|
|
211
|
+
"""
|
|
212
|
+
if not text:
|
|
213
|
+
return text
|
|
214
|
+
|
|
215
|
+
result = []
|
|
216
|
+
text_length = len(text)
|
|
217
|
+
color_rgb = ColorPalette.DIM_SCHEME_COLORS
|
|
218
|
+
|
|
219
|
+
for i, char in enumerate(text):
|
|
220
|
+
position = i / max(1, text_length - 1)
|
|
221
|
+
scaled_pos = position * (len(color_rgb) - 1)
|
|
222
|
+
color_index = int(scaled_pos)
|
|
223
|
+
t = scaled_pos - color_index
|
|
224
|
+
|
|
225
|
+
if color_index >= len(color_rgb) - 1:
|
|
226
|
+
r, g, b = color_rgb[-1]
|
|
227
|
+
else:
|
|
228
|
+
curr_rgb = color_rgb[color_index]
|
|
229
|
+
next_rgb = color_rgb[color_index + 1]
|
|
230
|
+
|
|
231
|
+
r = curr_rgb[0] + (next_rgb[0] - curr_rgb[0]) * t
|
|
232
|
+
g = curr_rgb[1] + (next_rgb[1] - curr_rgb[1]) * t
|
|
233
|
+
b = curr_rgb[2] + (next_rgb[2] - curr_rgb[2]) * t
|
|
234
|
+
|
|
235
|
+
r, g, b = int(r), int(g), int(b)
|
|
236
|
+
color_code = f"\033[38;2;{r};{g};{b}m"
|
|
237
|
+
result.append(f"{color_code}{char}")
|
|
238
|
+
|
|
239
|
+
result.append(ColorPalette.RESET)
|
|
240
|
+
return "".join(result)
|
|
241
|
+
|
|
242
|
+
@staticmethod
|
|
243
|
+
def apply_custom_gradient(text: str, colors: List[Tuple[int, int, int]]) -> str:
|
|
244
|
+
"""Apply custom RGB gradient to text.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
text: Text to apply gradient to.
|
|
248
|
+
colors: List of RGB color tuples for gradient stops.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Text with custom gradient applied.
|
|
252
|
+
"""
|
|
253
|
+
if not text or len(colors) < 2:
|
|
254
|
+
return text
|
|
255
|
+
|
|
256
|
+
result = []
|
|
257
|
+
text_length = len(text)
|
|
258
|
+
|
|
259
|
+
for i, char in enumerate(text):
|
|
260
|
+
position = i / max(1, text_length - 1)
|
|
261
|
+
scaled_pos = position * (len(colors) - 1)
|
|
262
|
+
color_index = int(scaled_pos)
|
|
263
|
+
t = scaled_pos - color_index
|
|
264
|
+
|
|
265
|
+
if color_index >= len(colors) - 1:
|
|
266
|
+
r, g, b = colors[-1]
|
|
267
|
+
else:
|
|
268
|
+
curr_rgb = colors[color_index]
|
|
269
|
+
next_rgb = colors[color_index + 1]
|
|
270
|
+
|
|
271
|
+
r = curr_rgb[0] + (next_rgb[0] - curr_rgb[0]) * t
|
|
272
|
+
g = curr_rgb[1] + (next_rgb[1] - curr_rgb[1]) * t
|
|
273
|
+
b = curr_rgb[2] + (next_rgb[2] - curr_rgb[2]) * t
|
|
274
|
+
|
|
275
|
+
r, g, b = int(r), int(g), int(b)
|
|
276
|
+
color_code = f"\033[38;2;{r};{g};{b}m"
|
|
277
|
+
result.append(f"{color_code}{char}")
|
|
278
|
+
|
|
279
|
+
result.append(ColorPalette.RESET)
|
|
280
|
+
return "".join(result)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class ShimmerEffect:
|
|
284
|
+
"""Handles shimmer animation effects."""
|
|
285
|
+
|
|
286
|
+
def __init__(self, speed: int = 3, wave_width: int = 4):
|
|
287
|
+
"""Initialize shimmer effect.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
speed: Animation speed (frames between updates).
|
|
291
|
+
wave_width: Width of shimmer wave in characters.
|
|
292
|
+
"""
|
|
293
|
+
self.speed = speed
|
|
294
|
+
self.wave_width = wave_width
|
|
295
|
+
self.frame_counter = 0
|
|
296
|
+
self.position = 0
|
|
297
|
+
|
|
298
|
+
def configure(self, speed: int, wave_width: int) -> None:
|
|
299
|
+
"""Configure shimmer parameters.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
speed: Animation speed.
|
|
303
|
+
wave_width: Wave width.
|
|
304
|
+
"""
|
|
305
|
+
self.speed = speed
|
|
306
|
+
self.wave_width = wave_width
|
|
307
|
+
|
|
308
|
+
def apply_shimmer(self, text: str) -> str:
|
|
309
|
+
"""Apply elegant wave shimmer effect to text.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
text: Text to apply shimmer to.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
Text with shimmer effect applied.
|
|
316
|
+
"""
|
|
317
|
+
if not text:
|
|
318
|
+
return text
|
|
319
|
+
|
|
320
|
+
# Update shimmer position
|
|
321
|
+
self.frame_counter = (self.frame_counter + 1) % self.speed
|
|
322
|
+
if self.frame_counter == 0:
|
|
323
|
+
self.position = (self.position + 1) % (len(text) + self.wave_width * 2)
|
|
324
|
+
|
|
325
|
+
result = []
|
|
326
|
+
for i, char in enumerate(text):
|
|
327
|
+
distance = abs(i - self.position)
|
|
328
|
+
|
|
329
|
+
if distance == 0:
|
|
330
|
+
# Center - bright cyan
|
|
331
|
+
result.append(
|
|
332
|
+
f"{ColorPalette.BRIGHT_CYAN}{char}{ColorPalette.RESET}"
|
|
333
|
+
)
|
|
334
|
+
elif distance == 1:
|
|
335
|
+
# Adjacent - bright blue
|
|
336
|
+
result.append(
|
|
337
|
+
f"{ColorPalette.BRIGHT_BLUE}{char}{ColorPalette.RESET}"
|
|
338
|
+
)
|
|
339
|
+
elif distance == 2:
|
|
340
|
+
# Second ring - normal blue
|
|
341
|
+
result.append(
|
|
342
|
+
f"{ColorPalette.NORMAL_BLUE}{char}{ColorPalette.RESET}"
|
|
343
|
+
)
|
|
344
|
+
elif distance <= self.wave_width:
|
|
345
|
+
# Edge - dim blue
|
|
346
|
+
result.append(f"{ColorPalette.DIM_BLUE}{char}{ColorPalette.RESET}")
|
|
347
|
+
else:
|
|
348
|
+
# Base - darker dim blue
|
|
349
|
+
result.append(f"\033[2;94m{char}{ColorPalette.RESET}")
|
|
350
|
+
|
|
351
|
+
return "".join(result)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class StatusColorizer:
|
|
355
|
+
"""Handles semantic coloring of status text with ASCII icons."""
|
|
356
|
+
|
|
357
|
+
# ASCII icon mapping (no emojis)
|
|
358
|
+
ASCII_ICONS = {
|
|
359
|
+
"checkmark": "√",
|
|
360
|
+
"error": "×",
|
|
361
|
+
"processing": "*",
|
|
362
|
+
"active": "+",
|
|
363
|
+
"inactive": "-",
|
|
364
|
+
"ratio": "::",
|
|
365
|
+
"arrow_right": ">",
|
|
366
|
+
"separator": "|",
|
|
367
|
+
"loading": "...",
|
|
368
|
+
"count": "#",
|
|
369
|
+
"circle_filled": "●",
|
|
370
|
+
"circle_empty": "○",
|
|
371
|
+
"circle_dot": "•",
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@staticmethod
|
|
375
|
+
def get_ascii_icon(icon_type: str) -> str:
|
|
376
|
+
"""Get ASCII icon by type.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
icon_type: Type of icon to retrieve.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
ASCII character for the icon.
|
|
383
|
+
"""
|
|
384
|
+
return StatusColorizer.ASCII_ICONS.get(icon_type, "")
|
|
385
|
+
|
|
386
|
+
@staticmethod
|
|
387
|
+
def apply_status_colors(text: str) -> str:
|
|
388
|
+
"""Apply semantic colors to status line text with ASCII icons.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
text: Status text to colorize.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Colorized text with ANSI codes and ASCII icons.
|
|
395
|
+
"""
|
|
396
|
+
# Replace emoji-style indicators with ASCII equivalents
|
|
397
|
+
text = text.replace(
|
|
398
|
+
"🟢",
|
|
399
|
+
f"{ColorPalette.BRIGHT_GREEN}"
|
|
400
|
+
f"{StatusColorizer.ASCII_ICONS['circle_filled']}"
|
|
401
|
+
f"{ColorPalette.RESET}",
|
|
402
|
+
)
|
|
403
|
+
text = text.replace(
|
|
404
|
+
"🟡",
|
|
405
|
+
f"{ColorPalette.DIM_YELLOW}"
|
|
406
|
+
f"{StatusColorizer.ASCII_ICONS['circle_filled']}"
|
|
407
|
+
f"{ColorPalette.RESET}",
|
|
408
|
+
)
|
|
409
|
+
text = text.replace(
|
|
410
|
+
"🔴",
|
|
411
|
+
f"{ColorPalette.DIM_RED}"
|
|
412
|
+
f"{StatusColorizer.ASCII_ICONS['circle_filled']}"
|
|
413
|
+
f"{ColorPalette.RESET}",
|
|
414
|
+
)
|
|
415
|
+
text = text.replace(
|
|
416
|
+
"✅",
|
|
417
|
+
f"{ColorPalette.BRIGHT_GREEN}"
|
|
418
|
+
f"{StatusColorizer.ASCII_ICONS['checkmark']}"
|
|
419
|
+
f"{ColorPalette.RESET}",
|
|
420
|
+
)
|
|
421
|
+
text = text.replace(
|
|
422
|
+
"❌",
|
|
423
|
+
f"{ColorPalette.DIM_RED}"
|
|
424
|
+
f"{StatusColorizer.ASCII_ICONS['error']}"
|
|
425
|
+
f"{ColorPalette.RESET}",
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
# Number/count highlighting (dim cyan for metrics)
|
|
429
|
+
text = re.sub(
|
|
430
|
+
r"\b(\d{1,3}(?:,\d{3})*)\b",
|
|
431
|
+
f"{ColorPalette.DIM_CYAN}\\1{ColorPalette.RESET}",
|
|
432
|
+
text,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# ASCII icon patterns
|
|
436
|
+
text = re.sub(
|
|
437
|
+
r"\b(✓)\s*",
|
|
438
|
+
f"{ColorPalette.BRIGHT_GREEN}\\1{ColorPalette.RESET} ",
|
|
439
|
+
text,
|
|
440
|
+
) # Checkmarks
|
|
441
|
+
text = re.sub(
|
|
442
|
+
r"\b(×)\s*",
|
|
443
|
+
f"{ColorPalette.DIM_RED}\\1{ColorPalette.RESET} ",
|
|
444
|
+
text,
|
|
445
|
+
) # Errors
|
|
446
|
+
text = re.sub(
|
|
447
|
+
r"\b(\*)\s*",
|
|
448
|
+
f"{ColorPalette.DIM_YELLOW}\\1{ColorPalette.RESET} ",
|
|
449
|
+
text,
|
|
450
|
+
) # Processing
|
|
451
|
+
text = re.sub(
|
|
452
|
+
r"\b(\+)\s*",
|
|
453
|
+
f"{ColorPalette.BRIGHT_GREEN}\\1{ColorPalette.RESET} ",
|
|
454
|
+
text,
|
|
455
|
+
) # Active
|
|
456
|
+
text = re.sub(
|
|
457
|
+
r"(^|\s)(-)\s+",
|
|
458
|
+
f"\\1{ColorPalette.DIM_CYAN}\\2{ColorPalette.RESET} ",
|
|
459
|
+
text,
|
|
460
|
+
) # Inactive (list markers only)
|
|
461
|
+
|
|
462
|
+
# Status indicators
|
|
463
|
+
text = re.sub(
|
|
464
|
+
r"\b(Processing: Yes)\b",
|
|
465
|
+
f"{ColorPalette.DIM_YELLOW}\\1{ColorPalette.RESET}",
|
|
466
|
+
text,
|
|
467
|
+
)
|
|
468
|
+
text = re.sub(
|
|
469
|
+
r"\b(Processing: No)\b",
|
|
470
|
+
f"{ColorPalette.BRIGHT_GREEN}\\1{ColorPalette.RESET}",
|
|
471
|
+
text,
|
|
472
|
+
)
|
|
473
|
+
text = re.sub(
|
|
474
|
+
r"\b(Ready)\b",
|
|
475
|
+
f"{ColorPalette.BRIGHT_GREEN}\\1{ColorPalette.RESET}",
|
|
476
|
+
text,
|
|
477
|
+
)
|
|
478
|
+
text = re.sub(
|
|
479
|
+
r"\b(Active)\b",
|
|
480
|
+
f"{ColorPalette.DIM_YELLOW}\\1{ColorPalette.RESET}",
|
|
481
|
+
text,
|
|
482
|
+
)
|
|
483
|
+
text = re.sub(
|
|
484
|
+
r"\b(On)\b",
|
|
485
|
+
f"{ColorPalette.DIM_YELLOW}\\1{ColorPalette.RESET}",
|
|
486
|
+
text,
|
|
487
|
+
)
|
|
488
|
+
text = re.sub(
|
|
489
|
+
r"\b(Off)\b",
|
|
490
|
+
f"{ColorPalette.DIM_CYAN}\\1{ColorPalette.RESET}",
|
|
491
|
+
text,
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
# Queue states
|
|
495
|
+
text = re.sub(
|
|
496
|
+
r"\b(Queue: 0)\b",
|
|
497
|
+
f"{ColorPalette.BRIGHT_GREEN}\\1{ColorPalette.RESET}",
|
|
498
|
+
text,
|
|
499
|
+
)
|
|
500
|
+
text = re.sub(
|
|
501
|
+
r"\b(Queue: [1-9][0-9]*)\b",
|
|
502
|
+
f"{ColorPalette.DIM_YELLOW}\\1{ColorPalette.RESET}",
|
|
503
|
+
text,
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
# Time measurements
|
|
507
|
+
text = re.sub(
|
|
508
|
+
r"\b(\d+\.\d+s)\b",
|
|
509
|
+
f"{ColorPalette.DIM_MAGENTA}\\1{ColorPalette.RESET}",
|
|
510
|
+
text,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Ratio highlighting (with :: separator)
|
|
514
|
+
text = re.sub(
|
|
515
|
+
r"\b(\d+):(\d+)\b",
|
|
516
|
+
f"{ColorPalette.DIM_BLUE}\\1{ColorPalette.DIM_CYAN}::"
|
|
517
|
+
f"{ColorPalette.DIM_BLUE}\\2{ColorPalette.RESET}",
|
|
518
|
+
text,
|
|
519
|
+
)
|
|
520
|
+
text = re.sub(
|
|
521
|
+
r"\b(Enhanced: \d+/\d+)",
|
|
522
|
+
f"{ColorPalette.DIM_BLUE}\\1{ColorPalette.RESET}",
|
|
523
|
+
text,
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# Percentage highlighting
|
|
527
|
+
text = re.sub(
|
|
528
|
+
r"\b(\d+\.\d+%)\b",
|
|
529
|
+
f"{ColorPalette.DIM_MAGENTA}\\1{ColorPalette.RESET}",
|
|
530
|
+
text,
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
# Token highlighting
|
|
534
|
+
text = re.sub(
|
|
535
|
+
r"\b(\d+\s*tok)\b",
|
|
536
|
+
f"{ColorPalette.DIM_CYAN}\\1{ColorPalette.RESET}",
|
|
537
|
+
text,
|
|
538
|
+
)
|
|
539
|
+
text = re.sub(
|
|
540
|
+
r"\b(\d+K\s*tok)\b",
|
|
541
|
+
f"{ColorPalette.DIM_CYAN}\\1{ColorPalette.RESET}",
|
|
542
|
+
text,
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
return text
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
class BannerRenderer:
|
|
549
|
+
"""Handles ASCII banner creation and rendering."""
|
|
550
|
+
|
|
551
|
+
KOLLABOR_ASCII2 = [
|
|
552
|
+
"██╗ ██╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ ██████╗ ",
|
|
553
|
+
"██║ ██╔╝██╔═══██╗██║ ██║ ██╔══██╗██╔══██╗██╔═══██╗██╔══██╗",
|
|
554
|
+
"█████╔╝ ██║ ██║██║ ██║ ███████║██████╔╝██║ ██║██████╔╝",
|
|
555
|
+
"██╔═██╗ ██║ ██║██║ ██║ ██╔══██║██╔══██╗██║ ██║██╔══██╗",
|
|
556
|
+
"██║ ██╗╚██████╔╝███████╗███████╗██║ ██║██████╔╝╚██████╔╝██║ ██║",
|
|
557
|
+
"╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝",
|
|
558
|
+
]
|
|
559
|
+
|
|
560
|
+
KOLLABOR_ASCII_v1 = [
|
|
561
|
+
"▒█░▄▀ █▀▀█ █░░ █░░ █▀▀█ █▀▀▄ █▀▀█ █▀▀█ █▀▀█ ▀█▀",
|
|
562
|
+
"▒█▀▄░ █░░█ █░░ █░░ █▄▄█ █▀▀▄ █░░█ █▄▄▀ █▄▄█ ░█░",
|
|
563
|
+
"▒█░▒█ ▀▀▀▀ ▀▀▀ ▀▀▀ ▀░░▀ ▀▀▀░ ▀▀▀▀ ▀░▀▀ ▄ ▀░░▀ ▄█▄",
|
|
564
|
+
]
|
|
565
|
+
KOLLABOR_ASCII_v2 = [
|
|
566
|
+
"\r ──────────────────────────────────────────────── ",
|
|
567
|
+
"\r █ ▄▀ █▀▀█ █ █ █▀▀█ █▀▀▄ █▀▀█ █▀▀█ █▀▀█ ▀█▀ ",
|
|
568
|
+
"\r █▀▄ █ █ █ █ █▄▄█ █▀▀▄ █ █ █▄▄▀ █▄▄█ █ ",
|
|
569
|
+
"\r ▀ ▀ ▀▀▀▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀▀▀ ",
|
|
570
|
+
"\r ──────────────────────────────────────────────── ",
|
|
571
|
+
]
|
|
572
|
+
KOLLABOR_ASCII = [
|
|
573
|
+
"\r ██╗ ██╔════════════════════════════════════════════╗",
|
|
574
|
+
"\r ██║ ██╔╝ ║",
|
|
575
|
+
"\r █████╔╝ █▀▀█ █ █ █▀▀█ █▀▀▄ █▀▀█ █▀▀█ █▀▀█ ▀█▀ ║",
|
|
576
|
+
"\r ██╔═██╗ █ █ █ █ █▄▄█ █▀▀▄ █ █ █▄▄▀ █▄▄█ █ ║",
|
|
577
|
+
"\r ██║ ██╗▀▀▀▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀▀▀ ║",
|
|
578
|
+
"\r ╚═╝ ╚═╩════════════════════════════════════════════╝",
|
|
579
|
+
]
|
|
580
|
+
|
|
581
|
+
@classmethod
|
|
582
|
+
def create_kollabor_banner(cls, version: str = "v1.0.0") -> str:
|
|
583
|
+
"""Create beautiful Kollabor ASCII banner with gradient.
|
|
584
|
+
|
|
585
|
+
Args:
|
|
586
|
+
version: Version string to display.
|
|
587
|
+
|
|
588
|
+
Returns:
|
|
589
|
+
Formatted banner with gradient colors and version.
|
|
590
|
+
"""
|
|
591
|
+
gradient_lines = []
|
|
592
|
+
for i, line in enumerate(cls.KOLLABOR_ASCII):
|
|
593
|
+
gradient_line = GradientRenderer.apply_dim_scheme_gradient(line)
|
|
594
|
+
|
|
595
|
+
# Add version to first line
|
|
596
|
+
if i == 0:
|
|
597
|
+
gradient_line += f" {ColorPalette.DIM}{version}{ColorPalette.RESET}"
|
|
598
|
+
|
|
599
|
+
gradient_lines.append(gradient_line)
|
|
600
|
+
|
|
601
|
+
return f"\n{chr(10).join(gradient_lines)}\n"
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
class VisualEffects:
|
|
605
|
+
"""Main visual effects coordinator."""
|
|
606
|
+
|
|
607
|
+
def __init__(self):
|
|
608
|
+
"""Initialize visual effects system."""
|
|
609
|
+
self.gradient_renderer = GradientRenderer()
|
|
610
|
+
self.shimmer_effect = ShimmerEffect()
|
|
611
|
+
self.status_colorizer = StatusColorizer()
|
|
612
|
+
self.banner_renderer = BannerRenderer()
|
|
613
|
+
|
|
614
|
+
# Effect configurations
|
|
615
|
+
self._effects_config: Dict[str, EffectConfig] = {
|
|
616
|
+
"thinking": EffectConfig(EffectType.SHIMMER, speed=3, width=4),
|
|
617
|
+
"gradient": EffectConfig(EffectType.GRADIENT),
|
|
618
|
+
"status": EffectConfig(EffectType.COLOR),
|
|
619
|
+
"banner": EffectConfig(EffectType.GRADIENT),
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
def configure_effect(self, effect_name: str, **kwargs) -> None:
|
|
623
|
+
"""Configure a specific effect.
|
|
624
|
+
|
|
625
|
+
Args:
|
|
626
|
+
effect_name: Name of effect to configure.
|
|
627
|
+
**kwargs: Configuration parameters.
|
|
628
|
+
"""
|
|
629
|
+
if effect_name in self._effects_config:
|
|
630
|
+
config = self._effects_config[effect_name]
|
|
631
|
+
for key, value in kwargs.items():
|
|
632
|
+
if hasattr(config, key):
|
|
633
|
+
setattr(config, key, value)
|
|
634
|
+
|
|
635
|
+
# Special handling for shimmer effect
|
|
636
|
+
if effect_name == "thinking":
|
|
637
|
+
self.shimmer_effect.configure(
|
|
638
|
+
kwargs.get("speed", 3), kwargs.get("width", 4)
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
def apply_thinking_effect(self, text: str, effect_type: str = "shimmer") -> str:
|
|
642
|
+
"""Apply thinking visualization effect.
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
text: Text to apply effect to.
|
|
646
|
+
effect_type: Type of effect ("shimmer", "dim", "normal").
|
|
647
|
+
|
|
648
|
+
Returns:
|
|
649
|
+
Text with thinking effect applied.
|
|
650
|
+
"""
|
|
651
|
+
config = self._effects_config.get("thinking")
|
|
652
|
+
if not config or not config.enabled:
|
|
653
|
+
return text
|
|
654
|
+
|
|
655
|
+
if effect_type == "shimmer":
|
|
656
|
+
return self.shimmer_effect.apply_shimmer(text)
|
|
657
|
+
elif effect_type == "dim":
|
|
658
|
+
return f"{ColorPalette.DIM}{text}{ColorPalette.RESET}"
|
|
659
|
+
else:
|
|
660
|
+
return text
|
|
661
|
+
|
|
662
|
+
def apply_message_gradient(
|
|
663
|
+
self, text: str, gradient_type: str = "dim_white"
|
|
664
|
+
) -> str:
|
|
665
|
+
"""Apply gradient effect to message text.
|
|
666
|
+
|
|
667
|
+
Args:
|
|
668
|
+
text: Text to apply gradient to.
|
|
669
|
+
gradient_type: Type of gradient to apply.
|
|
670
|
+
|
|
671
|
+
Returns:
|
|
672
|
+
Text with gradient applied.
|
|
673
|
+
"""
|
|
674
|
+
config = self._effects_config.get("gradient")
|
|
675
|
+
if not config or not config.enabled:
|
|
676
|
+
return text
|
|
677
|
+
|
|
678
|
+
if gradient_type == "white_to_grey":
|
|
679
|
+
return self.gradient_renderer.apply_white_to_grey(text)
|
|
680
|
+
elif gradient_type == "dim_white":
|
|
681
|
+
return self.gradient_renderer.apply_dim_white_gradient(text)
|
|
682
|
+
elif gradient_type == "dim_scheme":
|
|
683
|
+
return self.gradient_renderer.apply_dim_scheme_gradient(text)
|
|
684
|
+
else:
|
|
685
|
+
return text
|
|
686
|
+
|
|
687
|
+
def apply_status_colors(self, text: str) -> str:
|
|
688
|
+
"""Apply status colors to text.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
text: Text to colorize.
|
|
692
|
+
|
|
693
|
+
Returns:
|
|
694
|
+
Colorized text.
|
|
695
|
+
"""
|
|
696
|
+
config = self._effects_config.get("status")
|
|
697
|
+
if not config or not config.enabled:
|
|
698
|
+
return text
|
|
699
|
+
|
|
700
|
+
return self.status_colorizer.apply_status_colors(text)
|
|
701
|
+
|
|
702
|
+
def create_banner(self, version: str = "v1.0.0") -> str:
|
|
703
|
+
"""Create application banner.
|
|
704
|
+
|
|
705
|
+
Args:
|
|
706
|
+
version: Version string.
|
|
707
|
+
|
|
708
|
+
Returns:
|
|
709
|
+
Formatted banner.
|
|
710
|
+
"""
|
|
711
|
+
config = self._effects_config.get("banner")
|
|
712
|
+
if not config or not config.enabled:
|
|
713
|
+
return f"KOLLABOR {version}\n"
|
|
714
|
+
|
|
715
|
+
return self.banner_renderer.create_kollabor_banner(version)
|
|
716
|
+
|
|
717
|
+
def get_effect_stats(self) -> Dict[str, Any]:
|
|
718
|
+
"""Get visual effects statistics.
|
|
719
|
+
|
|
720
|
+
Returns:
|
|
721
|
+
Dictionary with effect statistics.
|
|
722
|
+
"""
|
|
723
|
+
return {
|
|
724
|
+
"shimmer_position": self.shimmer_effect.position,
|
|
725
|
+
"shimmer_frame_counter": self.shimmer_effect.frame_counter,
|
|
726
|
+
"effects_config": {
|
|
727
|
+
name: {
|
|
728
|
+
"enabled": config.enabled,
|
|
729
|
+
"type": getattr(config.effect_type, "value", config.effect_type),
|
|
730
|
+
"intensity": config.intensity,
|
|
731
|
+
}
|
|
732
|
+
for name, config in self._effects_config.items()
|
|
733
|
+
},
|
|
734
|
+
}
|