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.
Files changed (192) hide show
  1. agents/__init__.py +2 -0
  2. agents/coder/__init__.py +0 -0
  3. agents/coder/agent.json +4 -0
  4. agents/coder/api-integration.md +2150 -0
  5. agents/coder/cli-pretty.md +765 -0
  6. agents/coder/code-review.md +1092 -0
  7. agents/coder/database-design.md +1525 -0
  8. agents/coder/debugging.md +1102 -0
  9. agents/coder/dependency-management.md +1397 -0
  10. agents/coder/git-workflow.md +1099 -0
  11. agents/coder/refactoring.md +1454 -0
  12. agents/coder/security-hardening.md +1732 -0
  13. agents/coder/system_prompt.md +1448 -0
  14. agents/coder/tdd.md +1367 -0
  15. agents/creative-writer/__init__.py +0 -0
  16. agents/creative-writer/agent.json +4 -0
  17. agents/creative-writer/character-development.md +1852 -0
  18. agents/creative-writer/dialogue-craft.md +1122 -0
  19. agents/creative-writer/plot-structure.md +1073 -0
  20. agents/creative-writer/revision-editing.md +1484 -0
  21. agents/creative-writer/system_prompt.md +690 -0
  22. agents/creative-writer/worldbuilding.md +2049 -0
  23. agents/data-analyst/__init__.py +30 -0
  24. agents/data-analyst/agent.json +4 -0
  25. agents/data-analyst/data-visualization.md +992 -0
  26. agents/data-analyst/exploratory-data-analysis.md +1110 -0
  27. agents/data-analyst/pandas-data-manipulation.md +1081 -0
  28. agents/data-analyst/sql-query-optimization.md +881 -0
  29. agents/data-analyst/statistical-analysis.md +1118 -0
  30. agents/data-analyst/system_prompt.md +928 -0
  31. agents/default/__init__.py +0 -0
  32. agents/default/agent.json +4 -0
  33. agents/default/dead-code.md +794 -0
  34. agents/default/explore-agent-system.md +585 -0
  35. agents/default/system_prompt.md +1448 -0
  36. agents/kollabor/__init__.py +0 -0
  37. agents/kollabor/analyze-plugin-lifecycle.md +175 -0
  38. agents/kollabor/analyze-terminal-rendering.md +388 -0
  39. agents/kollabor/code-review.md +1092 -0
  40. agents/kollabor/debug-mcp-integration.md +521 -0
  41. agents/kollabor/debug-plugin-hooks.md +547 -0
  42. agents/kollabor/debugging.md +1102 -0
  43. agents/kollabor/dependency-management.md +1397 -0
  44. agents/kollabor/git-workflow.md +1099 -0
  45. agents/kollabor/inspect-llm-conversation.md +148 -0
  46. agents/kollabor/monitor-event-bus.md +558 -0
  47. agents/kollabor/profile-performance.md +576 -0
  48. agents/kollabor/refactoring.md +1454 -0
  49. agents/kollabor/system_prompt copy.md +1448 -0
  50. agents/kollabor/system_prompt.md +757 -0
  51. agents/kollabor/trace-command-execution.md +178 -0
  52. agents/kollabor/validate-config.md +879 -0
  53. agents/research/__init__.py +0 -0
  54. agents/research/agent.json +4 -0
  55. agents/research/architecture-mapping.md +1099 -0
  56. agents/research/codebase-analysis.md +1077 -0
  57. agents/research/dependency-audit.md +1027 -0
  58. agents/research/performance-profiling.md +1047 -0
  59. agents/research/security-review.md +1359 -0
  60. agents/research/system_prompt.md +492 -0
  61. agents/technical-writer/__init__.py +0 -0
  62. agents/technical-writer/agent.json +4 -0
  63. agents/technical-writer/api-documentation.md +2328 -0
  64. agents/technical-writer/changelog-management.md +1181 -0
  65. agents/technical-writer/readme-writing.md +1360 -0
  66. agents/technical-writer/style-guide.md +1410 -0
  67. agents/technical-writer/system_prompt.md +653 -0
  68. agents/technical-writer/tutorial-creation.md +1448 -0
  69. core/__init__.py +0 -2
  70. core/application.py +343 -88
  71. core/cli.py +229 -10
  72. core/commands/menu_renderer.py +463 -59
  73. core/commands/registry.py +14 -9
  74. core/commands/system_commands.py +2461 -14
  75. core/config/loader.py +151 -37
  76. core/config/service.py +18 -6
  77. core/events/bus.py +29 -9
  78. core/events/executor.py +205 -75
  79. core/events/models.py +27 -8
  80. core/fullscreen/command_integration.py +20 -24
  81. core/fullscreen/components/__init__.py +10 -1
  82. core/fullscreen/components/matrix_components.py +1 -2
  83. core/fullscreen/components/space_shooter_components.py +654 -0
  84. core/fullscreen/plugin.py +5 -0
  85. core/fullscreen/renderer.py +52 -13
  86. core/fullscreen/session.py +52 -15
  87. core/io/__init__.py +29 -5
  88. core/io/buffer_manager.py +6 -1
  89. core/io/config_status_view.py +7 -29
  90. core/io/core_status_views.py +267 -347
  91. core/io/input/__init__.py +25 -0
  92. core/io/input/command_mode_handler.py +711 -0
  93. core/io/input/display_controller.py +128 -0
  94. core/io/input/hook_registrar.py +286 -0
  95. core/io/input/input_loop_manager.py +421 -0
  96. core/io/input/key_press_handler.py +502 -0
  97. core/io/input/modal_controller.py +1011 -0
  98. core/io/input/paste_processor.py +339 -0
  99. core/io/input/status_modal_renderer.py +184 -0
  100. core/io/input_errors.py +5 -1
  101. core/io/input_handler.py +211 -2452
  102. core/io/key_parser.py +7 -0
  103. core/io/layout.py +15 -3
  104. core/io/message_coordinator.py +111 -2
  105. core/io/message_renderer.py +129 -4
  106. core/io/status_renderer.py +147 -607
  107. core/io/terminal_renderer.py +97 -51
  108. core/io/terminal_state.py +21 -4
  109. core/io/visual_effects.py +816 -165
  110. core/llm/agent_manager.py +1063 -0
  111. core/llm/api_adapters/__init__.py +44 -0
  112. core/llm/api_adapters/anthropic_adapter.py +432 -0
  113. core/llm/api_adapters/base.py +241 -0
  114. core/llm/api_adapters/openai_adapter.py +326 -0
  115. core/llm/api_communication_service.py +167 -113
  116. core/llm/conversation_logger.py +322 -16
  117. core/llm/conversation_manager.py +556 -30
  118. core/llm/file_operations_executor.py +84 -32
  119. core/llm/llm_service.py +934 -103
  120. core/llm/mcp_integration.py +541 -57
  121. core/llm/message_display_service.py +135 -18
  122. core/llm/plugin_sdk.py +1 -2
  123. core/llm/profile_manager.py +1183 -0
  124. core/llm/response_parser.py +274 -56
  125. core/llm/response_processor.py +16 -3
  126. core/llm/tool_executor.py +6 -1
  127. core/logging/__init__.py +2 -0
  128. core/logging/setup.py +34 -6
  129. core/models/resume.py +54 -0
  130. core/plugins/__init__.py +4 -2
  131. core/plugins/base.py +127 -0
  132. core/plugins/collector.py +23 -161
  133. core/plugins/discovery.py +37 -3
  134. core/plugins/factory.py +6 -12
  135. core/plugins/registry.py +5 -17
  136. core/ui/config_widgets.py +128 -28
  137. core/ui/live_modal_renderer.py +2 -1
  138. core/ui/modal_actions.py +5 -0
  139. core/ui/modal_overlay_renderer.py +0 -60
  140. core/ui/modal_renderer.py +268 -7
  141. core/ui/modal_state_manager.py +29 -4
  142. core/ui/widgets/base_widget.py +7 -0
  143. core/updates/__init__.py +10 -0
  144. core/updates/version_check_service.py +348 -0
  145. core/updates/version_comparator.py +103 -0
  146. core/utils/config_utils.py +685 -526
  147. core/utils/plugin_utils.py +1 -1
  148. core/utils/session_naming.py +111 -0
  149. fonts/LICENSE +21 -0
  150. fonts/README.md +46 -0
  151. fonts/SymbolsNerdFont-Regular.ttf +0 -0
  152. fonts/SymbolsNerdFontMono-Regular.ttf +0 -0
  153. fonts/__init__.py +44 -0
  154. {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/METADATA +54 -4
  155. kollabor-0.4.15.dist-info/RECORD +228 -0
  156. {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/top_level.txt +2 -0
  157. plugins/agent_orchestrator/__init__.py +39 -0
  158. plugins/agent_orchestrator/activity_monitor.py +181 -0
  159. plugins/agent_orchestrator/file_attacher.py +77 -0
  160. plugins/agent_orchestrator/message_injector.py +135 -0
  161. plugins/agent_orchestrator/models.py +48 -0
  162. plugins/agent_orchestrator/orchestrator.py +403 -0
  163. plugins/agent_orchestrator/plugin.py +976 -0
  164. plugins/agent_orchestrator/xml_parser.py +191 -0
  165. plugins/agent_orchestrator_plugin.py +9 -0
  166. plugins/enhanced_input/box_styles.py +1 -0
  167. plugins/enhanced_input/color_engine.py +19 -4
  168. plugins/enhanced_input/config.py +2 -2
  169. plugins/enhanced_input_plugin.py +61 -11
  170. plugins/fullscreen/__init__.py +6 -2
  171. plugins/fullscreen/example_plugin.py +1035 -222
  172. plugins/fullscreen/setup_wizard_plugin.py +592 -0
  173. plugins/fullscreen/space_shooter_plugin.py +131 -0
  174. plugins/hook_monitoring_plugin.py +436 -78
  175. plugins/query_enhancer_plugin.py +66 -30
  176. plugins/resume_conversation_plugin.py +1494 -0
  177. plugins/save_conversation_plugin.py +98 -32
  178. plugins/system_commands_plugin.py +70 -56
  179. plugins/tmux_plugin.py +154 -78
  180. plugins/workflow_enforcement_plugin.py +94 -92
  181. system_prompt/default.md +952 -886
  182. core/io/input_mode_manager.py +0 -402
  183. core/io/modal_interaction_handler.py +0 -315
  184. core/io/raw_input_processor.py +0 -946
  185. core/storage/__init__.py +0 -5
  186. core/storage/state_manager.py +0 -84
  187. core/ui/widget_integration.py +0 -222
  188. core/utils/key_reader.py +0 -171
  189. kollabor-0.4.9.dist-info/RECORD +0 -128
  190. {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/WHEEL +0 -0
  191. {kollabor-0.4.9.dist-info → kollabor-0.4.15.dist-info}/entry_points.txt +0 -0
  192. {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.