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,765 @@
|
|
|
1
|
+
<!-- CLI Pretty skill - terminal UI styling with powerline, colors, and unicode -->
|
|
2
|
+
|
|
3
|
+
cli-pretty mode: MAKE TERMINALS BEAUTIFUL
|
|
4
|
+
|
|
5
|
+
when this skill is active, you follow terminal aesthetic excellence.
|
|
6
|
+
this is a comprehensive guide to creating stunning CLI interfaces that
|
|
7
|
+
make terminal junkies absolutely lose their minds.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
PHASE 0: UNDERSTAND THE KOLLABOR COLOR SYSTEM
|
|
11
|
+
|
|
12
|
+
before styling ANY terminal output, understand the color infrastructure.
|
|
13
|
+
|
|
14
|
+
location of color utilities:
|
|
15
|
+
core/io/visual_effects.py
|
|
16
|
+
|
|
17
|
+
key imports you will use:
|
|
18
|
+
from core.io.visual_effects import (
|
|
19
|
+
AgnosterSegment,
|
|
20
|
+
AgnosterColors,
|
|
21
|
+
ColorPalette,
|
|
22
|
+
make_bg_color,
|
|
23
|
+
make_fg_color,
|
|
24
|
+
Powerline
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
verify the file exists:
|
|
28
|
+
<terminal>ls -la core/io/visual_effects.py</terminal>
|
|
29
|
+
|
|
30
|
+
check available color classes:
|
|
31
|
+
<terminal>grep -n "class.*Color" core/io/visual_effects.py</terminal>
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
PHASE 1: ANSI ESCAPE CODE FUNDAMENTALS
|
|
35
|
+
|
|
36
|
+
ANSI codes control terminal styling. format: \033[<code>m
|
|
37
|
+
|
|
38
|
+
basic codes:
|
|
39
|
+
BOLD = "\033[1m" bold text
|
|
40
|
+
DIM = "\033[2m" dimmed text
|
|
41
|
+
ITALIC = "\033[3m" italic (not all terminals)
|
|
42
|
+
UNDERLINE = "\033[4m" underlined
|
|
43
|
+
BLINK = "\033[5m" blinking (avoid this)
|
|
44
|
+
REVERSE = "\033[7m" swap fg/bg
|
|
45
|
+
HIDDEN = "\033[8m" hidden text
|
|
46
|
+
RESET = "\033[0m" reset all formatting
|
|
47
|
+
|
|
48
|
+
foreground colors (30-37, 90-97 for bright):
|
|
49
|
+
BLACK = "\033[30m" BRIGHT_BLACK = "\033[90m"
|
|
50
|
+
RED = "\033[31m" BRIGHT_RED = "\033[91m"
|
|
51
|
+
GREEN = "\033[32m" BRIGHT_GREEN = "\033[92m"
|
|
52
|
+
YELLOW = "\033[33m" BRIGHT_YELLOW = "\033[93m"
|
|
53
|
+
BLUE = "\033[34m" BRIGHT_BLUE = "\033[94m"
|
|
54
|
+
MAGENTA = "\033[35m" BRIGHT_MAGENTA = "\033[95m"
|
|
55
|
+
CYAN = "\033[36m" BRIGHT_CYAN = "\033[96m"
|
|
56
|
+
WHITE = "\033[37m" BRIGHT_WHITE = "\033[97m"
|
|
57
|
+
|
|
58
|
+
background colors (40-47, 100-107 for bright):
|
|
59
|
+
BG_BLACK = "\033[40m" BG_BRIGHT_BLACK = "\033[100m"
|
|
60
|
+
BG_RED = "\033[41m" BG_BRIGHT_RED = "\033[101m"
|
|
61
|
+
BG_GREEN = "\033[42m" BG_BRIGHT_GREEN = "\033[102m"
|
|
62
|
+
BG_YELLOW = "\033[43m" BG_BRIGHT_YELLOW = "\033[103m"
|
|
63
|
+
BG_BLUE = "\033[44m" BG_BRIGHT_BLUE = "\033[104m"
|
|
64
|
+
BG_MAGENTA = "\033[45m" BG_BRIGHT_MAGENTA = "\033[105m"
|
|
65
|
+
BG_CYAN = "\033[46m" BG_BRIGHT_CYAN = "\033[106m"
|
|
66
|
+
BG_WHITE = "\033[47m" BG_BRIGHT_WHITE = "\033[107m"
|
|
67
|
+
|
|
68
|
+
combining codes (separate with semicolon):
|
|
69
|
+
"\033[1;32m" bold + green
|
|
70
|
+
"\033[1;97;44m" bold + white text + blue bg
|
|
71
|
+
"\033[102;30;1m" bright green bg + black text + bold
|
|
72
|
+
|
|
73
|
+
example usage:
|
|
74
|
+
print(f"\033[1;32mSuccess!\033[0m")
|
|
75
|
+
print(f"\033[41;97m ERROR \033[0m Something went wrong")
|
|
76
|
+
|
|
77
|
+
always RESET after styled text:
|
|
78
|
+
WRONG: print(f"\033[1mBold text")
|
|
79
|
+
RIGHT: print(f"\033[1mBold text\033[0m")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
PHASE 2: RGB AND 256-COLOR MODE
|
|
83
|
+
|
|
84
|
+
for richer colors, use 256-color or true color (24-bit RGB).
|
|
85
|
+
|
|
86
|
+
256-color foreground: \033[38;5;<color>m
|
|
87
|
+
256-color background: \033[48;5;<color>m
|
|
88
|
+
|
|
89
|
+
color ranges in 256 palette:
|
|
90
|
+
0-7 standard colors
|
|
91
|
+
8-15 bright colors
|
|
92
|
+
16-231 216-color cube (6x6x6)
|
|
93
|
+
232-255 grayscale (24 shades)
|
|
94
|
+
|
|
95
|
+
example:
|
|
96
|
+
"\033[38;5;208m" orange text (color 208)
|
|
97
|
+
"\033[48;5;17m" dark blue background
|
|
98
|
+
|
|
99
|
+
true color (24-bit RGB):
|
|
100
|
+
foreground: \033[38;2;<r>;<g>;<b>m
|
|
101
|
+
background: \033[48;2;<r>;<g>;<b>m
|
|
102
|
+
|
|
103
|
+
example:
|
|
104
|
+
"\033[38;2;163;230;53m" lime green text (rgb 163,230,53)
|
|
105
|
+
"\033[48;2;6;182;212m" cyan background (rgb 6,182,212)
|
|
106
|
+
|
|
107
|
+
kollabor helper functions:
|
|
108
|
+
make_fg_color(r, g, b) returns proper escape code for fg
|
|
109
|
+
make_bg_color(r, g, b) returns proper escape code for bg
|
|
110
|
+
|
|
111
|
+
these automatically detect terminal color support and fall back
|
|
112
|
+
to 256-color or basic colors if needed.
|
|
113
|
+
|
|
114
|
+
example with helpers:
|
|
115
|
+
from core.io.visual_effects import make_bg_color, make_fg_color
|
|
116
|
+
|
|
117
|
+
lime_bg = make_bg_color(163, 230, 53)
|
|
118
|
+
dark_text = make_fg_color(20, 20, 20)
|
|
119
|
+
reset = "\033[0m"
|
|
120
|
+
|
|
121
|
+
print(f"{lime_bg}{dark_text} SUCCESS {reset}")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
PHASE 3: AGNOSTER COLORS - THE SIGNATURE PALETTE
|
|
125
|
+
|
|
126
|
+
kollabor uses a specific color palette for consistency.
|
|
127
|
+
|
|
128
|
+
class AgnosterColors:
|
|
129
|
+
# lime palette (RGB tuples)
|
|
130
|
+
LIME = (163, 230, 53)
|
|
131
|
+
LIME_DARK = (132, 204, 22)
|
|
132
|
+
LIME_DARKER = (100, 160, 15)
|
|
133
|
+
|
|
134
|
+
# cyan palette
|
|
135
|
+
CYAN = (6, 182, 212)
|
|
136
|
+
CYAN_DARK = (8, 145, 178)
|
|
137
|
+
CYAN_LIGHT = (34, 211, 238)
|
|
138
|
+
|
|
139
|
+
# neutral backgrounds
|
|
140
|
+
BG_DARK = (30, 30, 30)
|
|
141
|
+
BG_MID = (50, 50, 50)
|
|
142
|
+
BG_LIGHT = (70, 70, 70)
|
|
143
|
+
|
|
144
|
+
# text colors
|
|
145
|
+
TEXT_DARK = (20, 20, 20)
|
|
146
|
+
TEXT_LIGHT = (240, 240, 240)
|
|
147
|
+
|
|
148
|
+
usage pattern:
|
|
149
|
+
from core.io.visual_effects import AgnosterColors, make_bg_color, make_fg_color
|
|
150
|
+
|
|
151
|
+
# create color codes from RGB tuples
|
|
152
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
153
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
154
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_DARK)
|
|
155
|
+
text_light = make_fg_color(*AgnosterColors.TEXT_LIGHT)
|
|
156
|
+
|
|
157
|
+
# use the * operator to unpack RGB tuple
|
|
158
|
+
# AgnosterColors.LIME = (163, 230, 53)
|
|
159
|
+
# make_bg_color(*AgnosterColors.LIME) = make_bg_color(163, 230, 53)
|
|
160
|
+
|
|
161
|
+
color philosophy:
|
|
162
|
+
- LIME for success, active, primary actions
|
|
163
|
+
- CYAN for info, secondary, navigation
|
|
164
|
+
- NEUTRAL for backgrounds, disabled, descriptions
|
|
165
|
+
- high contrast: dark text on light bg, light text on dark bg
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
PHASE 4: POWERLINE CHARACTERS
|
|
169
|
+
|
|
170
|
+
powerline fonts provide special separator characters for slick transitions.
|
|
171
|
+
|
|
172
|
+
key powerline characters:
|
|
173
|
+
PL_RIGHT = "" right-pointing triangle (\ue0b0)
|
|
174
|
+
PL_RIGHT_SOFT = "" right-pointing thin (\ue0b1)
|
|
175
|
+
PL_LEFT = "" left-pointing triangle (\ue0b2)
|
|
176
|
+
PL_LEFT_SOFT = "" left-pointing thin (\ue0b3)
|
|
177
|
+
|
|
178
|
+
how powerline transitions work:
|
|
179
|
+
[segment A bg][segment B bg color as fg][PL_RIGHT][segment B content]
|
|
180
|
+
|
|
181
|
+
the trick: the separator character uses:
|
|
182
|
+
- segment A background (continues the bg)
|
|
183
|
+
- segment B background color AS FOREGROUND (creates the arrow)
|
|
184
|
+
|
|
185
|
+
example building a powerline segment:
|
|
186
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
187
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
188
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_DARK)
|
|
189
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
190
|
+
reset = "\033[0m"
|
|
191
|
+
|
|
192
|
+
# segment 1: lime background
|
|
193
|
+
# separator: dark bg + lime fg (creates lime arrow into dark)
|
|
194
|
+
# segment 2: dark background
|
|
195
|
+
|
|
196
|
+
line = (
|
|
197
|
+
f"{lime_bg}{text_dark} ICON {reset}"
|
|
198
|
+
f"{dark_bg}{lime_fg}{PL_RIGHT}{reset}"
|
|
199
|
+
f"{dark_bg}{text_light} content {reset}"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
visual result:
|
|
203
|
+
ICON content
|
|
204
|
+
^ powerline separator creates smooth transition
|
|
205
|
+
|
|
206
|
+
pro tip: to fade to terminal background, use just the fg color:
|
|
207
|
+
f"{lime_fg}{PL_RIGHT}{reset}"
|
|
208
|
+
this creates an arrow that fades into the default terminal bg
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
PHASE 5: AGNOSTER SEGMENT BUILDER
|
|
212
|
+
|
|
213
|
+
AgnosterSegment is a builder class for creating powerline-style segments.
|
|
214
|
+
|
|
215
|
+
basic usage:
|
|
216
|
+
from core.io.visual_effects import AgnosterSegment
|
|
217
|
+
|
|
218
|
+
seg = AgnosterSegment()
|
|
219
|
+
seg.add_lime("Success")
|
|
220
|
+
seg.add_cyan("Info")
|
|
221
|
+
seg.add_neutral("Details", "dark")
|
|
222
|
+
result = seg.render()
|
|
223
|
+
|
|
224
|
+
available methods:
|
|
225
|
+
seg.add_lime(text, variant) variant: "normal", "dark", "darker"
|
|
226
|
+
seg.add_cyan(text, variant) variant: "normal", "dark", "light"
|
|
227
|
+
seg.add_neutral(text, variant) variant: "dark", "mid", "light"
|
|
228
|
+
seg.add(text, bg_rgb, fg_rgb) custom colors as RGB tuples
|
|
229
|
+
seg.render(separator) render with powerline separator
|
|
230
|
+
|
|
231
|
+
render options:
|
|
232
|
+
seg.render() uses default PL_RIGHT separator
|
|
233
|
+
seg.render(separator="") no separator (for single segments)
|
|
234
|
+
seg.render(separator=PL_LEFT) use left-pointing separator
|
|
235
|
+
|
|
236
|
+
example - status line:
|
|
237
|
+
seg = AgnosterSegment()
|
|
238
|
+
seg.add_lime("OK", "dark")
|
|
239
|
+
seg.add_cyan("3 items")
|
|
240
|
+
seg.add_neutral("ready", "mid")
|
|
241
|
+
print(seg.render())
|
|
242
|
+
|
|
243
|
+
output: OK 3 items ready
|
|
244
|
+
|
|
245
|
+
example - selected item with glow:
|
|
246
|
+
seg = AgnosterSegment()
|
|
247
|
+
seg.add_lime(" * ") glow indicator
|
|
248
|
+
seg.add_cyan(f" /{name} ") command name
|
|
249
|
+
seg.add_neutral(description) description fades out
|
|
250
|
+
print(seg.render())
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
PHASE 6: UNICODE SYMBOLS AND ICONS
|
|
254
|
+
|
|
255
|
+
unicode provides thousands of symbols for visual enhancement.
|
|
256
|
+
|
|
257
|
+
arrows:
|
|
258
|
+
ARROW_UP = "▲" solid up triangle
|
|
259
|
+
ARROW_DOWN = "▼" solid down triangle
|
|
260
|
+
ARROW_RIGHT = "▶" solid right triangle
|
|
261
|
+
ARROW_LEFT = "◀" solid left triangle
|
|
262
|
+
CHEVRON_RIGHT = "❯" chevron (commonly used for selection)
|
|
263
|
+
CHEVRON_LEFT = "❮" chevron left
|
|
264
|
+
|
|
265
|
+
geometric shapes:
|
|
266
|
+
DIAMOND = "◆" solid diamond (great for "glow" effect)
|
|
267
|
+
DIAMOND_OUTLINE = "◇" outline diamond
|
|
268
|
+
CIRCLE = "●" solid circle
|
|
269
|
+
CIRCLE_OUTLINE = "○" outline circle
|
|
270
|
+
SQUARE = "■" solid square
|
|
271
|
+
SQUARE_OUTLINE = "□" outline square
|
|
272
|
+
|
|
273
|
+
status indicators:
|
|
274
|
+
CHECK = "✓" checkmark
|
|
275
|
+
CROSS = "✗" x mark
|
|
276
|
+
BULLET = "•" bullet point
|
|
277
|
+
DOT = "·" middle dot (great for dot leaders)
|
|
278
|
+
ELLIPSIS = "…" horizontal ellipsis
|
|
279
|
+
|
|
280
|
+
category icons (used in kollabor menu):
|
|
281
|
+
GEAR = "⚙" system/settings
|
|
282
|
+
COMMAND = "⌘" command key (conversation)
|
|
283
|
+
OPTION = "⌥" option key (development)
|
|
284
|
+
DIAMOND_ICON = "◈" agent
|
|
285
|
+
MENU = "☰" hamburger menu (tasks)
|
|
286
|
+
BARS = "≡" three bars (files)
|
|
287
|
+
PLUS_CIRCLE = "⊕" circled plus (plugins)
|
|
288
|
+
|
|
289
|
+
special characters:
|
|
290
|
+
STAR = "★" solid star
|
|
291
|
+
STAR_OUTLINE = "☆" outline star
|
|
292
|
+
HEART = "♥" heart
|
|
293
|
+
LIGHTNING = "⚡" lightning bolt
|
|
294
|
+
FIRE = "🔥" fire (emoji - may not render in all terminals)
|
|
295
|
+
|
|
296
|
+
usage in menus:
|
|
297
|
+
CATEGORY_CONFIG = {
|
|
298
|
+
"system": {"name": "System", "icon": "⚙"},
|
|
299
|
+
"conversation": {"name": "Chat", "icon": "⌘"},
|
|
300
|
+
"plugins": {"name": "Plugins", "icon": "⊕"},
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
for cat, config in CATEGORY_CONFIG.items():
|
|
304
|
+
print(f" {config['icon']} {config['name']}")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
PHASE 7: BOX DRAWING CHARACTERS
|
|
308
|
+
|
|
309
|
+
box drawing creates frames, tables, and structured layouts.
|
|
310
|
+
|
|
311
|
+
single-line box:
|
|
312
|
+
TL = "┌" horizontal = "─" TR = "┐"
|
|
313
|
+
vertical = "│"
|
|
314
|
+
BL = "└" BR = "┘"
|
|
315
|
+
|
|
316
|
+
double-line box:
|
|
317
|
+
TL = "╔" horizontal = "═" TR = "╗"
|
|
318
|
+
vertical = "║"
|
|
319
|
+
BL = "╚" BR = "╝"
|
|
320
|
+
|
|
321
|
+
heavy/bold box:
|
|
322
|
+
TL = "┏" horizontal = "━" TR = "┓"
|
|
323
|
+
vertical = "┃"
|
|
324
|
+
BL = "┗" BR = "┛"
|
|
325
|
+
|
|
326
|
+
connectors (single):
|
|
327
|
+
T_DOWN = "┬" joins top edge to vertical down
|
|
328
|
+
T_UP = "┴" joins bottom edge to vertical up
|
|
329
|
+
T_RIGHT = "├" joins left edge to horizontal right
|
|
330
|
+
T_LEFT = "┤" joins right edge to horizontal left
|
|
331
|
+
CROSS = "┼" four-way intersection
|
|
332
|
+
|
|
333
|
+
connectors (heavy):
|
|
334
|
+
T_DOWN = "┳" T_UP = "┻" T_RIGHT = "┣"
|
|
335
|
+
T_LEFT = "┫" CROSS = "╋"
|
|
336
|
+
|
|
337
|
+
example - simple box:
|
|
338
|
+
width = 40
|
|
339
|
+
print(f"┌{'─' * width}┐")
|
|
340
|
+
print(f"│{'Content here'.center(width)}│")
|
|
341
|
+
print(f"└{'─' * width}┘")
|
|
342
|
+
|
|
343
|
+
output:
|
|
344
|
+
┌────────────────────────────────────────┐
|
|
345
|
+
│ Content here │
|
|
346
|
+
└────────────────────────────────────────┘
|
|
347
|
+
|
|
348
|
+
example - table:
|
|
349
|
+
print("┌──────────┬──────────┬──────────┐")
|
|
350
|
+
print("│ Name │ Status │ Count │")
|
|
351
|
+
print("├──────────┼──────────┼──────────┤")
|
|
352
|
+
print("│ Alpha │ Active │ 42 │")
|
|
353
|
+
print("│ Beta │ Pending │ 17 │")
|
|
354
|
+
print("└──────────┴──────────┴──────────┘")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
PHASE 8: DOT LEADERS AND ALIGNMENT
|
|
358
|
+
|
|
359
|
+
dot leaders connect labels to values across space.
|
|
360
|
+
|
|
361
|
+
basic dot leader:
|
|
362
|
+
DOT = "·"
|
|
363
|
+
|
|
364
|
+
label = "/help"
|
|
365
|
+
description = "Show available commands"
|
|
366
|
+
padding = 25 - len(label)
|
|
367
|
+
dots = DOT * padding
|
|
368
|
+
|
|
369
|
+
print(f" {label} {dots} {description}")
|
|
370
|
+
|
|
371
|
+
output:
|
|
372
|
+
/help ··················· Show available commands
|
|
373
|
+
|
|
374
|
+
calculating padding:
|
|
375
|
+
max_width = 25
|
|
376
|
+
name = "/config"
|
|
377
|
+
padding_len = max_width - len(name) - 2 # -2 for spaces
|
|
378
|
+
dots = DOT * max(2, padding_len) # minimum 2 dots
|
|
379
|
+
|
|
380
|
+
line = f" {name} {dots} {description}"
|
|
381
|
+
|
|
382
|
+
combining with colors:
|
|
383
|
+
BOLD = "\033[1m"
|
|
384
|
+
DIM = "\033[2m"
|
|
385
|
+
RESET = "\033[0m"
|
|
386
|
+
CYAN = "\033[36m"
|
|
387
|
+
|
|
388
|
+
line = f" {CYAN}{BOLD}{name}{RESET} {DIM}{dots} {description}{RESET}"
|
|
389
|
+
|
|
390
|
+
alignment techniques:
|
|
391
|
+
# right-align numbers
|
|
392
|
+
count = 42
|
|
393
|
+
print(f"Items: {count:>5}") # "Items: 42"
|
|
394
|
+
|
|
395
|
+
# left-align with padding
|
|
396
|
+
name = "test"
|
|
397
|
+
print(f"{name:<10} | description") # "test | description"
|
|
398
|
+
|
|
399
|
+
# center
|
|
400
|
+
title = "MENU"
|
|
401
|
+
print(f"{title:^20}") # " MENU "
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
PHASE 9: SCROLL INDICATORS
|
|
405
|
+
|
|
406
|
+
scroll indicators show when content extends beyond visible area.
|
|
407
|
+
|
|
408
|
+
basic scroll indicator:
|
|
409
|
+
ARROW_UP = "▲"
|
|
410
|
+
ARROW_DOWN = "▼"
|
|
411
|
+
|
|
412
|
+
if has_more_above:
|
|
413
|
+
print(f" {ARROW_UP} {count} more above")
|
|
414
|
+
|
|
415
|
+
if has_more_below:
|
|
416
|
+
print(f" {ARROW_DOWN} {count} more below")
|
|
417
|
+
|
|
418
|
+
styled scroll indicator with powerline:
|
|
419
|
+
def make_scroll_indicator(direction, count):
|
|
420
|
+
arrow = "▲" if direction == "up" else "▼"
|
|
421
|
+
|
|
422
|
+
cyan_bg = make_bg_color(*AgnosterColors.CYAN_DARK)
|
|
423
|
+
cyan_fg = make_fg_color(*AgnosterColors.CYAN_DARK)
|
|
424
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
425
|
+
reset = "\033[0m"
|
|
426
|
+
bold = "\033[1m"
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
f"{cyan_bg}{text_dark} {arrow} {bold}{count}{reset}"
|
|
430
|
+
f"{cyan_bg} {reset}{cyan_fg}{PL_RIGHT}{reset}"
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
print(make_scroll_indicator("up", 3))
|
|
434
|
+
print(make_scroll_indicator("down", 5))
|
|
435
|
+
|
|
436
|
+
scroll state management:
|
|
437
|
+
scroll_offset = 0
|
|
438
|
+
max_visible = 8
|
|
439
|
+
total_items = 20
|
|
440
|
+
|
|
441
|
+
has_more_above = scroll_offset > 0
|
|
442
|
+
has_more_below = scroll_offset + max_visible < total_items
|
|
443
|
+
|
|
444
|
+
items_above = scroll_offset
|
|
445
|
+
items_below = total_items - (scroll_offset + max_visible)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
PHASE 10: SELECTED ITEM HIGHLIGHTING
|
|
449
|
+
|
|
450
|
+
selected items need strong visual distinction.
|
|
451
|
+
|
|
452
|
+
simple highlight (reverse video):
|
|
453
|
+
REVERSE = "\033[7m"
|
|
454
|
+
RESET = "\033[0m"
|
|
455
|
+
|
|
456
|
+
for i, item in enumerate(items):
|
|
457
|
+
if i == selected_index:
|
|
458
|
+
print(f"{REVERSE} {item} {RESET}")
|
|
459
|
+
else:
|
|
460
|
+
print(f" {item}")
|
|
461
|
+
|
|
462
|
+
powerline highlight with glow:
|
|
463
|
+
GLOW = "◆"
|
|
464
|
+
|
|
465
|
+
def format_item(name, description, is_selected):
|
|
466
|
+
if is_selected:
|
|
467
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
468
|
+
cyan_bg = make_bg_color(*AgnosterColors.CYAN)
|
|
469
|
+
cyan_fg = make_fg_color(*AgnosterColors.CYAN)
|
|
470
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
471
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_MID)
|
|
472
|
+
dark_fg = make_fg_color(*AgnosterColors.BG_MID)
|
|
473
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
474
|
+
text_light = make_fg_color(*AgnosterColors.TEXT_LIGHT)
|
|
475
|
+
|
|
476
|
+
return (
|
|
477
|
+
f"{lime_bg}{text_dark} {GLOW} {RESET}"
|
|
478
|
+
f"{cyan_bg}{lime_fg}{PL_RIGHT}{RESET}"
|
|
479
|
+
f"{cyan_bg}{text_dark}{BOLD} {name} {RESET}"
|
|
480
|
+
f"{dark_bg}{cyan_fg}{PL_RIGHT}{RESET}"
|
|
481
|
+
f"{dark_bg}{text_light} {description} {RESET}"
|
|
482
|
+
f"{dark_fg}{PL_RIGHT}{RESET}"
|
|
483
|
+
)
|
|
484
|
+
else:
|
|
485
|
+
return f" {name} {DIM}{description}{RESET}"
|
|
486
|
+
|
|
487
|
+
visual result:
|
|
488
|
+
* /selected Description here <- full powerline glow
|
|
489
|
+
/other ······· Other description <- subtle, dimmed
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
PHASE 11: CATEGORY HEADERS
|
|
493
|
+
|
|
494
|
+
category headers group related items with visual separation.
|
|
495
|
+
|
|
496
|
+
simple category header:
|
|
497
|
+
def format_category(name, icon):
|
|
498
|
+
return f"\n {icon} {name}\n"
|
|
499
|
+
|
|
500
|
+
powerline category header:
|
|
501
|
+
def format_category_header(category):
|
|
502
|
+
config = {
|
|
503
|
+
"system": {"icon": "⚙", "name": "System"},
|
|
504
|
+
"plugins": {"icon": "⊕", "name": "Plugins"},
|
|
505
|
+
}.get(category, {"icon": "?", "name": category})
|
|
506
|
+
|
|
507
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
508
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
509
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_DARK)
|
|
510
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
511
|
+
text_light = make_fg_color(*AgnosterColors.TEXT_LIGHT)
|
|
512
|
+
|
|
513
|
+
return (
|
|
514
|
+
f"{lime_bg}{text_dark}{BOLD} {config['icon']} {RESET}"
|
|
515
|
+
f"{dark_bg}{lime_fg}{PL_RIGHT}{RESET}"
|
|
516
|
+
f"{dark_bg}{text_light} {config['name']} {RESET}"
|
|
517
|
+
f"{lime_fg}{PL_RIGHT}{RESET}"
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
visual result:
|
|
521
|
+
⚙ System <- lime icon, dark name, fade out
|
|
522
|
+
/help ······ Show commands
|
|
523
|
+
/config ···· Configuration
|
|
524
|
+
⊕ Plugins
|
|
525
|
+
/matrix ···· Matrix rain effect
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
PHASE 12: PUTTING IT ALL TOGETHER - MENU EXAMPLE
|
|
529
|
+
|
|
530
|
+
complete menu implementation:
|
|
531
|
+
|
|
532
|
+
from core.io.visual_effects import (
|
|
533
|
+
AgnosterSegment, AgnosterColors, ColorPalette,
|
|
534
|
+
make_bg_color, make_fg_color
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
BOLD = "\033[1m"
|
|
538
|
+
DIM = "\033[2m"
|
|
539
|
+
RESET = ColorPalette.RESET
|
|
540
|
+
PL_RIGHT = ""
|
|
541
|
+
DOT = "·"
|
|
542
|
+
ARROW_UP = "▲"
|
|
543
|
+
ARROW_DOWN = "▼"
|
|
544
|
+
GLOW = "◆"
|
|
545
|
+
|
|
546
|
+
class MenuRenderer:
|
|
547
|
+
def render_menu(self, commands, selected_idx, scroll_offset):
|
|
548
|
+
lines = []
|
|
549
|
+
|
|
550
|
+
# scroll up indicator
|
|
551
|
+
if scroll_offset > 0:
|
|
552
|
+
lines.append(self._scroll_indicator("up", scroll_offset))
|
|
553
|
+
|
|
554
|
+
# visible items
|
|
555
|
+
current_category = None
|
|
556
|
+
for i, cmd in enumerate(commands[scroll_offset:scroll_offset+8]):
|
|
557
|
+
real_idx = scroll_offset + i
|
|
558
|
+
|
|
559
|
+
# category header
|
|
560
|
+
if cmd["category"] != current_category:
|
|
561
|
+
current_category = cmd["category"]
|
|
562
|
+
lines.append(self._category_header(current_category))
|
|
563
|
+
|
|
564
|
+
# command line
|
|
565
|
+
is_selected = real_idx == selected_idx
|
|
566
|
+
lines.append(self._command_line(cmd, is_selected))
|
|
567
|
+
|
|
568
|
+
# scroll down indicator
|
|
569
|
+
remaining = len(commands) - scroll_offset - 8
|
|
570
|
+
if remaining > 0:
|
|
571
|
+
lines.append(self._scroll_indicator("down", remaining))
|
|
572
|
+
|
|
573
|
+
return "\n".join(lines)
|
|
574
|
+
|
|
575
|
+
def _scroll_indicator(self, direction, count):
|
|
576
|
+
arrow = ARROW_UP if direction == "up" else ARROW_DOWN
|
|
577
|
+
seg = AgnosterSegment()
|
|
578
|
+
seg.add_cyan(f" {arrow} {count} ", "dark")
|
|
579
|
+
return seg.render(separator="")
|
|
580
|
+
|
|
581
|
+
def _category_header(self, category):
|
|
582
|
+
icons = {"system": "⚙", "plugins": "⊕"}
|
|
583
|
+
icon = icons.get(category, "?")
|
|
584
|
+
|
|
585
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
586
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
587
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_DARK)
|
|
588
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
589
|
+
text_light = make_fg_color(*AgnosterColors.TEXT_LIGHT)
|
|
590
|
+
|
|
591
|
+
return (
|
|
592
|
+
f"{lime_bg}{text_dark}{BOLD} {icon} {RESET}"
|
|
593
|
+
f"{dark_bg}{lime_fg}{PL_RIGHT}{RESET}"
|
|
594
|
+
f"{dark_bg}{text_light} {category.title()} {RESET}"
|
|
595
|
+
f"{lime_fg}{PL_RIGHT}{RESET}"
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
def _command_line(self, cmd, is_selected):
|
|
599
|
+
name = cmd["name"]
|
|
600
|
+
desc = cmd.get("description", "")[:35]
|
|
601
|
+
|
|
602
|
+
if is_selected:
|
|
603
|
+
# full powerline glow
|
|
604
|
+
lime_bg = make_bg_color(*AgnosterColors.LIME)
|
|
605
|
+
cyan_bg = make_bg_color(*AgnosterColors.CYAN)
|
|
606
|
+
cyan_fg = make_fg_color(*AgnosterColors.CYAN)
|
|
607
|
+
lime_fg = make_fg_color(*AgnosterColors.LIME)
|
|
608
|
+
dark_bg = make_bg_color(*AgnosterColors.BG_MID)
|
|
609
|
+
dark_fg = make_fg_color(*AgnosterColors.BG_MID)
|
|
610
|
+
text_dark = make_fg_color(*AgnosterColors.TEXT_DARK)
|
|
611
|
+
text_light = make_fg_color(*AgnosterColors.TEXT_LIGHT)
|
|
612
|
+
|
|
613
|
+
return (
|
|
614
|
+
f"{lime_bg}{text_dark}{BOLD} {GLOW} {RESET}"
|
|
615
|
+
f"{cyan_bg}{lime_fg}{PL_RIGHT}{RESET}"
|
|
616
|
+
f"{cyan_bg}{text_dark}{BOLD} /{name} {RESET}"
|
|
617
|
+
f"{dark_bg}{cyan_fg}{PL_RIGHT}{RESET}"
|
|
618
|
+
f"{dark_bg}{text_light} {desc} {RESET}"
|
|
619
|
+
f"{dark_fg}{PL_RIGHT}{RESET}"
|
|
620
|
+
)
|
|
621
|
+
else:
|
|
622
|
+
# subtle with dot leaders
|
|
623
|
+
dots = DOT * (18 - len(name))
|
|
624
|
+
mid_bg = make_bg_color(*AgnosterColors.BG_DARK)
|
|
625
|
+
mid_fg = make_fg_color(*AgnosterColors.BG_DARK)
|
|
626
|
+
cyan_fg = make_fg_color(*AgnosterColors.CYAN)
|
|
627
|
+
|
|
628
|
+
return (
|
|
629
|
+
f" {mid_bg}{cyan_fg}{BOLD} /{name} {RESET}"
|
|
630
|
+
f"{mid_fg}{PL_RIGHT}{RESET}"
|
|
631
|
+
f" {DIM}{dots} {desc}{RESET}"
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
PHASE 13: TERMINAL WIDTH AND RESPONSIVE DESIGN
|
|
636
|
+
|
|
637
|
+
adapt layouts to terminal width.
|
|
638
|
+
|
|
639
|
+
get terminal size:
|
|
640
|
+
import shutil
|
|
641
|
+
|
|
642
|
+
width, height = shutil.get_terminal_size()
|
|
643
|
+
# or
|
|
644
|
+
import os
|
|
645
|
+
width = os.get_terminal_size().columns
|
|
646
|
+
|
|
647
|
+
responsive truncation:
|
|
648
|
+
def truncate(text, max_len):
|
|
649
|
+
if len(text) <= max_len:
|
|
650
|
+
return text
|
|
651
|
+
return text[:max_len-2] + ".."
|
|
652
|
+
|
|
653
|
+
# use available width
|
|
654
|
+
term_width = shutil.get_terminal_size().columns
|
|
655
|
+
name_width = 20
|
|
656
|
+
desc_width = term_width - name_width - 10 # padding
|
|
657
|
+
description = truncate(full_description, desc_width)
|
|
658
|
+
|
|
659
|
+
responsive layouts:
|
|
660
|
+
if term_width < 60:
|
|
661
|
+
# compact mode: name only
|
|
662
|
+
print(f" /{name}")
|
|
663
|
+
elif term_width < 100:
|
|
664
|
+
# medium: name + short description
|
|
665
|
+
print(f" /{name:<15} {description[:30]}")
|
|
666
|
+
else:
|
|
667
|
+
# full: powerline with everything
|
|
668
|
+
print(full_powerline_format)
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
PHASE 14: COLOR SUPPORT DETECTION
|
|
672
|
+
|
|
673
|
+
detect and adapt to terminal color capabilities.
|
|
674
|
+
|
|
675
|
+
kollabor color detection:
|
|
676
|
+
from core.io.visual_effects import get_color_support, ColorSupport
|
|
677
|
+
|
|
678
|
+
support = get_color_support()
|
|
679
|
+
|
|
680
|
+
if support == ColorSupport.TRUE_COLOR:
|
|
681
|
+
# full 24-bit RGB
|
|
682
|
+
color = make_fg_color(163, 230, 53)
|
|
683
|
+
elif support == ColorSupport.EXTENDED:
|
|
684
|
+
# 256 colors
|
|
685
|
+
color = "\033[38;5;154m" # approximate lime
|
|
686
|
+
elif support == ColorSupport.BASIC:
|
|
687
|
+
# 16 colors
|
|
688
|
+
color = "\033[92m" # bright green
|
|
689
|
+
else:
|
|
690
|
+
# no colors
|
|
691
|
+
color = ""
|
|
692
|
+
|
|
693
|
+
environment override:
|
|
694
|
+
KOLLABOR_COLOR_MODE=truecolor force 24-bit
|
|
695
|
+
KOLLABOR_COLOR_MODE=256 force 256-color
|
|
696
|
+
KOLLABOR_COLOR_MODE=none disable colors
|
|
697
|
+
NO_COLOR=1 standard no-color flag
|
|
698
|
+
|
|
699
|
+
graceful degradation:
|
|
700
|
+
make_fg_color() and make_bg_color() handle this automatically.
|
|
701
|
+
they detect color support and fall back appropriately.
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
PHASE 15: RULES FOR CLI PRETTINESS
|
|
705
|
+
|
|
706
|
+
while this skill is active, these rules are MANDATORY:
|
|
707
|
+
|
|
708
|
+
[1] ALWAYS RESET
|
|
709
|
+
every styled string must end with \033[0m or RESET
|
|
710
|
+
leaked styles corrupt all subsequent output
|
|
711
|
+
|
|
712
|
+
[2] USE THE PALETTE
|
|
713
|
+
stick to AgnosterColors for consistency
|
|
714
|
+
LIME for primary/success, CYAN for secondary/info
|
|
715
|
+
|
|
716
|
+
[3] CONTRAST IS KING
|
|
717
|
+
dark text on light backgrounds
|
|
718
|
+
light text on dark backgrounds
|
|
719
|
+
never light-on-light or dark-on-dark
|
|
720
|
+
|
|
721
|
+
[4] POWERLINE TRANSITIONS
|
|
722
|
+
separator fg = previous segment bg color
|
|
723
|
+
this creates the smooth arrow effect
|
|
724
|
+
|
|
725
|
+
[5] TEST IN MULTIPLE TERMINALS
|
|
726
|
+
iterm2, terminal.app, vscode, alacritty
|
|
727
|
+
colors render differently everywhere
|
|
728
|
+
|
|
729
|
+
[6] RESPECT NO_COLOR
|
|
730
|
+
check for NO_COLOR env var
|
|
731
|
+
provide plain text fallback
|
|
732
|
+
|
|
733
|
+
[7] KEEP IT READABLE
|
|
734
|
+
pretty > unreadable
|
|
735
|
+
dim non-essential info
|
|
736
|
+
highlight what matters
|
|
737
|
+
|
|
738
|
+
[8] UNICODE FALLBACKS
|
|
739
|
+
not all terminals support all unicode
|
|
740
|
+
have ASCII alternatives ready
|
|
741
|
+
PL_RIGHT "" might need ">" fallback
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
FINAL REMINDERS
|
|
745
|
+
|
|
746
|
+
beauty is not decoration. it is communication.
|
|
747
|
+
- color draws attention to what matters
|
|
748
|
+
- structure creates scannable hierarchy
|
|
749
|
+
- contrast separates concerns
|
|
750
|
+
|
|
751
|
+
terminal junkies appreciate:
|
|
752
|
+
- powerline transitions (not boxes everywhere)
|
|
753
|
+
- consistent color language
|
|
754
|
+
- subtle animations (not disco)
|
|
755
|
+
- dense information display
|
|
756
|
+
- keyboard-first interaction
|
|
757
|
+
|
|
758
|
+
the kollabor signature:
|
|
759
|
+
- lime for success, active, primary
|
|
760
|
+
- cyan for info, navigation, secondary
|
|
761
|
+
- powerline separators between segments
|
|
762
|
+
- dot leaders for alignment
|
|
763
|
+
- unicode icons for categories
|
|
764
|
+
|
|
765
|
+
go make something beautiful.
|