kader 0.1.5__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.
cli/app.tcss ADDED
@@ -0,0 +1,664 @@
1
+ /* Kader CLI - Modern Terminal UI Stylesheet */
2
+
3
+ /* ===== Color Themes ===== */
4
+
5
+ /* Default Dark Theme */
6
+ $primary: #7c3aed;
7
+ $secondary: #06b6d4;
8
+ $success: #10b981;
9
+ $warning: #f59e0b;
10
+ $error: #ef4444;
11
+ $surface: #1e1e2e;
12
+ $background: #11111b;
13
+ $text: #cdd6f4;
14
+ $text-muted: #6c7086;
15
+
16
+ /* ===== Root App ===== */
17
+
18
+ Screen {
19
+ background: $background;
20
+ min-width: 89;
21
+ min-height: 29;
22
+ }
23
+
24
+ /* ===== Size Warning Overlay ===== */
25
+
26
+ #size-warning {
27
+ dock: top;
28
+ width: 100%;
29
+ height: 100%;
30
+ background: $background 95%;
31
+ color: $warning;
32
+ text-align: center;
33
+ content-align: center middle;
34
+ text-style: bold;
35
+ padding: 2;
36
+ layer: overlay;
37
+ }
38
+
39
+ /* ===== Header ===== */
40
+
41
+ Header {
42
+ background: $primary;
43
+ color: $text;
44
+ text-style: bold;
45
+ height: 1;
46
+ dock: top;
47
+ }
48
+
49
+ /* ===== Footer ===== */
50
+
51
+ Footer {
52
+ background: $surface;
53
+ color: $text-muted;
54
+ height: 1;
55
+ dock: bottom;
56
+ }
57
+
58
+ FooterKey {
59
+ background: transparent;
60
+ color: $text-muted;
61
+ }
62
+
63
+ FooterKey > .footer-key--key {
64
+ background: $primary;
65
+ color: $text;
66
+ }
67
+
68
+ /* ===== Main Layout ===== */
69
+
70
+ #main-container {
71
+ layout: horizontal;
72
+ height: 1fr;
73
+ }
74
+
75
+ /* ===== Sidebar (Directory Tree) ===== */
76
+
77
+ #sidebar {
78
+ width: 22;
79
+ min-width: 18;
80
+ max-width: 35;
81
+ background: $surface;
82
+ border-right: thick $primary;
83
+ padding: 0;
84
+ }
85
+
86
+ #sidebar-title {
87
+ background: $primary 20%;
88
+ color: $text;
89
+ text-style: bold;
90
+ padding: 1;
91
+ text-align: center;
92
+ height: 3;
93
+ }
94
+
95
+ DirectoryTree {
96
+ background: transparent;
97
+ padding: 0 1;
98
+ scrollbar-size: 1 1;
99
+ }
100
+
101
+ DirectoryTree > .directory-tree--folder {
102
+ color: $secondary;
103
+ }
104
+
105
+ DirectoryTree > .directory-tree--file {
106
+ color: $text;
107
+ }
108
+
109
+ DirectoryTree > .directory-tree--extension {
110
+ color: $text-muted;
111
+ }
112
+
113
+ DirectoryTree:focus > .directory-tree--cursor {
114
+ background: $primary 40%;
115
+ }
116
+
117
+ /* ===== Content Area ===== */
118
+
119
+ #content-area {
120
+ width: 1fr;
121
+ layout: vertical;
122
+ }
123
+
124
+ /* ===== Conversation ===== */
125
+
126
+ #conversation {
127
+ height: 1fr;
128
+ background: $background;
129
+ }
130
+
131
+ ConversationView {
132
+ scrollbar-size: 1 1;
133
+ }
134
+
135
+ /* ===== Welcome Message ===== */
136
+
137
+ #welcome {
138
+ padding: 2 4;
139
+ text-align: center;
140
+ }
141
+
142
+ #welcome Markdown {
143
+ text-align: center;
144
+ }
145
+
146
+ /* ===== Input Area ===== */
147
+
148
+ #input-container {
149
+ height: auto;
150
+ min-height: 4;
151
+ max-height: 7;
152
+ background: $background;
153
+ padding: 1;
154
+ margin-bottom: 1;
155
+ }
156
+
157
+ #prompt-input {
158
+ background: transparent;
159
+ border: round $primary;
160
+ padding: 0 1;
161
+ height: 3;
162
+ }
163
+
164
+ #prompt-input:focus {
165
+ border: round $secondary;
166
+ }
167
+
168
+ Input.-valid {
169
+ border: round $success;
170
+ }
171
+
172
+ Input > .input--placeholder {
173
+ color: $text-muted;
174
+ text-style: italic;
175
+ }
176
+
177
+ /* ===== Loading Spinner ===== */
178
+
179
+ LoadingSpinner {
180
+ background: $surface;
181
+ margin: 0 2;
182
+ padding: 1;
183
+ border-left: thick $warning;
184
+ }
185
+
186
+ /* ===== Command Hints in Footer ===== */
187
+
188
+ #command-hints {
189
+ dock: bottom;
190
+ height: 1;
191
+ background: $surface;
192
+ padding: 0 1;
193
+ text-align: center;
194
+ }
195
+
196
+ .command-hint {
197
+ margin: 0 1;
198
+ color: $text-muted;
199
+ }
200
+
201
+ .command-key {
202
+ color: $primary;
203
+ text-style: bold;
204
+ }
205
+
206
+ /* ===== Markdown Styling ===== */
207
+
208
+ Markdown {
209
+ margin: 0;
210
+ padding: 0;
211
+ }
212
+
213
+ MarkdownH1 {
214
+ color: $primary;
215
+ text-style: bold underline;
216
+ margin: 1 0;
217
+ }
218
+
219
+ MarkdownH2 {
220
+ color: $secondary;
221
+ text-style: bold;
222
+ margin: 1 0;
223
+ }
224
+
225
+ MarkdownH3 {
226
+ color: $success;
227
+ text-style: bold;
228
+ margin: 1 0;
229
+ }
230
+
231
+ MarkdownFence {
232
+ background: $surface;
233
+ border: round #6c7086;
234
+ margin: 1 0;
235
+ padding: 1;
236
+ }
237
+
238
+ MarkdownBlockQuote {
239
+ background: $primary 10%;
240
+ border-left: thick $primary;
241
+ padding: 0 1;
242
+ margin: 1 0;
243
+ }
244
+
245
+ MarkdownBulletList {
246
+ margin: 0;
247
+ padding-left: 2;
248
+ }
249
+
250
+ MarkdownTable {
251
+ margin: 1 0;
252
+ }
253
+
254
+ MarkdownTH {
255
+ background: $primary 20%;
256
+ text-style: bold;
257
+ }
258
+
259
+ MarkdownTD {
260
+ padding: 0 1;
261
+ }
262
+
263
+ /* ===== Scrollbars ===== */
264
+
265
+ Scrollbar {
266
+ background: $surface;
267
+ }
268
+
269
+ ScrollbarSlider {
270
+ color: $primary;
271
+ }
272
+
273
+ ScrollbarSlider:hover {
274
+ color: $secondary;
275
+ }
276
+
277
+ /* ===== Theme Variants ===== */
278
+
279
+ /* Ocean Theme */
280
+ .theme-ocean Screen {
281
+ background: #0f172a;
282
+ }
283
+
284
+ .theme-ocean Header {
285
+ background: #3b82f6;
286
+ color: #f1f5f9;
287
+ }
288
+
289
+ .theme-ocean Footer {
290
+ background: #1e293b;
291
+ color: #94a3b8;
292
+ }
293
+
294
+ .theme-ocean FooterKey > .footer-key--key {
295
+ background: #3b82f6;
296
+ color: #f1f5f9;
297
+ }
298
+
299
+ .theme-ocean #sidebar {
300
+ background: #1e293b;
301
+ border-right: thick #3b82f6;
302
+ }
303
+
304
+ .theme-ocean #sidebar-title {
305
+ background: #3b82f6 20%;
306
+ color: #f1f5f9;
307
+ }
308
+
309
+ .theme-ocean DirectoryTree > .directory-tree--folder {
310
+ color: #06b6d4;
311
+ }
312
+
313
+ .theme-ocean DirectoryTree > .directory-tree--file {
314
+ color: #f1f5f9;
315
+ }
316
+
317
+ .theme-ocean DirectoryTree > .directory-tree--extension {
318
+ color: #94a3b8;
319
+ }
320
+
321
+ .theme-ocean DirectoryTree:focus > .directory-tree--cursor {
322
+ background: #3b82f6 40%;
323
+ }
324
+
325
+ .theme-ocean #conversation {
326
+ background: #0f172a;
327
+ border-bottom: thick #1e293b;
328
+ }
329
+
330
+ .theme-ocean #input-container {
331
+ background: #1e293b;
332
+ border-top: thick #3b82f6;
333
+ }
334
+
335
+ .theme-ocean #prompt-input {
336
+ background: #0f172a;
337
+ border: round #3b82f6;
338
+ }
339
+
340
+ .theme-ocean #prompt-input:focus {
341
+ border: round #06b6d4;
342
+ }
343
+
344
+ .theme-ocean Input.-valid {
345
+ border: round #10b981;
346
+ }
347
+
348
+ .theme-ocean Input > .input--placeholder {
349
+ color: #94a3b8;
350
+ text-style: italic;
351
+ }
352
+
353
+ .theme-ocean LoadingSpinner {
354
+ background: #1e293b;
355
+ border-left: thick #f59e0b;
356
+ }
357
+
358
+ .theme-ocean #command-hints {
359
+ background: #1e293b;
360
+ }
361
+
362
+ .theme-ocean .command-hint {
363
+ color: #94a3b8;
364
+ }
365
+
366
+ .theme-ocean .command-key {
367
+ color: #3b82f6;
368
+ }
369
+
370
+ .theme-ocean MarkdownH1 {
371
+ color: #3b82f6;
372
+ }
373
+
374
+ .theme-ocean MarkdownH2 {
375
+ color: #06b6d4;
376
+ }
377
+
378
+ .theme-ocean MarkdownH3 {
379
+ color: #10b981;
380
+ }
381
+
382
+ .theme-ocean MarkdownFence {
383
+ background: #1e293b;
384
+ border: round #94a3b8;
385
+ }
386
+
387
+ .theme-ocean MarkdownBlockQuote {
388
+ background: #3b82f6 10%;
389
+ border-left: thick #3b82f6;
390
+ }
391
+
392
+ .theme-ocean MarkdownTH {
393
+ background: #3b82f6 20%;
394
+ }
395
+
396
+ .theme-ocean Scrollbar {
397
+ background: #1e293b;
398
+ }
399
+
400
+ .theme-ocean ScrollbarSlider {
401
+ color: #3b82f6;
402
+ }
403
+
404
+ .theme-ocean ScrollbarSlider:hover {
405
+ color: #06b6d4;
406
+ }
407
+
408
+ /* Forest Theme */
409
+ .theme-forest Screen {
410
+ background: #0d1f0d;
411
+ }
412
+
413
+ .theme-forest Header {
414
+ background: #16a34a;
415
+ color: #dcfce7;
416
+ }
417
+
418
+ .theme-forest Footer {
419
+ background: #0f2f0f;
420
+ color: #6ee7b7;
421
+ }
422
+
423
+ .theme-forest FooterKey > .footer-key--key {
424
+ background: #16a34a;
425
+ color: #dcfce7;
426
+ }
427
+
428
+ .theme-forest #sidebar {
429
+ background: #0f2f0f;
430
+ border-right: thick #16a34a;
431
+ }
432
+
433
+ .theme-forest #sidebar-title {
434
+ background: #16a34a 20%;
435
+ color: #dcfce7;
436
+ }
437
+
438
+ .theme-forest DirectoryTree > .directory-tree--folder {
439
+ color: #0891b2;
440
+ }
441
+
442
+ .theme-forest DirectoryTree > .directory-tree--file {
443
+ color: #dcfce7;
444
+ }
445
+
446
+ .theme-forest DirectoryTree > .directory-tree--extension {
447
+ color: #6ee7b7;
448
+ }
449
+
450
+ .theme-forest DirectoryTree:focus > .directory-tree--cursor {
451
+ background: #16a34a 40%;
452
+ }
453
+
454
+ .theme-forest #conversation {
455
+ background: #0d1f0d;
456
+ border-bottom: thick #0f2f0f;
457
+ }
458
+
459
+ .theme-forest #input-container {
460
+ background: #0f2f0f;
461
+ border-top: thick #16a34a;
462
+ }
463
+
464
+ .theme-forest #prompt-input {
465
+ background: #0d1f0d;
466
+ border: round #16a34a;
467
+ }
468
+
469
+ .theme-forest #prompt-input:focus {
470
+ border: round #0891b2;
471
+ }
472
+
473
+ .theme-forest Input.-valid {
474
+ border: round #22c55e;
475
+ }
476
+
477
+ .theme-forest Input > .input--placeholder {
478
+ color: #6ee7b7;
479
+ text-style: italic;
480
+ }
481
+
482
+ .theme-forest LoadingSpinner {
483
+ background: #0f2f0f;
484
+ border-left: thick #eab308;
485
+ }
486
+
487
+ .theme-forest #command-hints {
488
+ background: #0f2f0f;
489
+ }
490
+
491
+ .theme-forest .command-hint {
492
+ color: #6ee7b7;
493
+ }
494
+
495
+ .theme-forest .command-key {
496
+ color: #16a34a;
497
+ }
498
+
499
+ .theme-forest MarkdownH1 {
500
+ color: #16a34a;
501
+ }
502
+
503
+ .theme-forest MarkdownH2 {
504
+ color: #0891b2;
505
+ }
506
+
507
+ .theme-forest MarkdownH3 {
508
+ color: #22c55e;
509
+ }
510
+
511
+ .theme-forest MarkdownFence {
512
+ background: #0f2f0f;
513
+ border: round #6ee7b7;
514
+ }
515
+
516
+ .theme-forest MarkdownBlockQuote {
517
+ background: #16a34a 10%;
518
+ border-left: thick #16a34a;
519
+ }
520
+
521
+ .theme-forest MarkdownTH {
522
+ background: #16a34a 20%;
523
+ }
524
+
525
+ .theme-forest Scrollbar {
526
+ background: #0f2f0f;
527
+ }
528
+
529
+ .theme-forest ScrollbarSlider {
530
+ color: #16a34a;
531
+ }
532
+
533
+ .theme-forest ScrollbarSlider:hover {
534
+ color: #0891b2;
535
+ }
536
+
537
+ /* Sunset Theme */
538
+ .theme-sunset Screen {
539
+ background: #1f1315;
540
+ }
541
+
542
+ .theme-sunset Header {
543
+ background: #dc2626;
544
+ color: #fef2f2;
545
+ }
546
+
547
+ .theme-sunset Footer {
548
+ background: #2f171a;
549
+ color: #fecaca;
550
+ }
551
+
552
+ .theme-sunset FooterKey > .footer-key--key {
553
+ background: #dc2626;
554
+ color: #fef2f2;
555
+ }
556
+
557
+ .theme-sunset #sidebar {
558
+ background: #2f171a;
559
+ border-right: thick #dc2626;
560
+ }
561
+
562
+ .theme-sunset #sidebar-title {
563
+ background: #dc2626 20%;
564
+ color: #fef2f2;
565
+ }
566
+
567
+ .theme-sunset DirectoryTree > .directory-tree--folder {
568
+ color: #ea580c;
569
+ }
570
+
571
+ .theme-sunset DirectoryTree > .directory-tree--file {
572
+ color: #fef2f2;
573
+ }
574
+
575
+ .theme-sunset DirectoryTree > .directory-tree--extension {
576
+ color: #fecaca;
577
+ }
578
+
579
+ .theme-sunset DirectoryTree:focus > .directory-tree--cursor {
580
+ background: #dc2626 40%;
581
+ }
582
+
583
+ .theme-sunset #conversation {
584
+ background: #1f1315;
585
+ border-bottom: thick #2f171a;
586
+ }
587
+
588
+ .theme-sunset #input-container {
589
+ background: #2f171a;
590
+ border-top: thick #dc2626;
591
+ }
592
+
593
+ .theme-sunset #prompt-input {
594
+ background: #1f1315;
595
+ border: round #dc2626;
596
+ }
597
+
598
+ .theme-sunset #prompt-input:focus {
599
+ border: round #ea580c;
600
+ }
601
+
602
+ .theme-sunset Input.-valid {
603
+ border: round #16a34a;
604
+ }
605
+
606
+ .theme-sunset Input > .input--placeholder {
607
+ color: #fecaca;
608
+ text-style: italic;
609
+ }
610
+
611
+ .theme-sunset LoadingSpinner {
612
+ background: #2f171a;
613
+ border-left: thick #eab308;
614
+ }
615
+
616
+ .theme-sunset #command-hints {
617
+ background: #2f171a;
618
+ }
619
+
620
+ .theme-sunset .command-hint {
621
+ color: #fecaca;
622
+ }
623
+
624
+ .theme-sunset .command-key {
625
+ color: #dc2626;
626
+ }
627
+
628
+ .theme-sunset MarkdownH1 {
629
+ color: #dc2626;
630
+ }
631
+
632
+ .theme-sunset MarkdownH2 {
633
+ color: #ea580c;
634
+ }
635
+
636
+ .theme-sunset MarkdownH3 {
637
+ color: #16a34a;
638
+ }
639
+
640
+ .theme-sunset MarkdownFence {
641
+ background: #2f171a;
642
+ border: round #fecaca;
643
+ }
644
+
645
+ .theme-sunset MarkdownBlockQuote {
646
+ background: #dc2626 10%;
647
+ border-left: thick #dc2626;
648
+ }
649
+
650
+ .theme-sunset MarkdownTH {
651
+ background: #dc2626 20%;
652
+ }
653
+
654
+ .theme-sunset Scrollbar {
655
+ background: #2f171a;
656
+ }
657
+
658
+ .theme-sunset ScrollbarSlider {
659
+ color: #dc2626;
660
+ }
661
+
662
+ .theme-sunset ScrollbarSlider:hover {
663
+ color: #ea580c;
664
+ }
cli/utils.py ADDED
@@ -0,0 +1,68 @@
1
+ """Utility constants and helpers for Kader CLI."""
2
+
3
+ from kader.providers import OllamaProvider
4
+
5
+ # Theme names for cycling
6
+ THEME_NAMES = ["dark", "ocean", "forest", "sunset"]
7
+
8
+ # Default model
9
+ DEFAULT_MODEL = "qwen3-coder:480b-cloud"
10
+
11
+ HELP_TEXT = """## Kader CLI Commands
12
+
13
+ | Command | Description |
14
+ |---------|-------------|
15
+ | `/models` | Show available LLM models |
16
+ | `/theme` | Cycle through color themes |
17
+ | `/help` | Show this help message |
18
+ | `/clear` | Clear the conversation |
19
+ | `/save` | Save current session |
20
+ | `/load <id>` | Load a saved session |
21
+ | `/sessions` | List saved sessions |
22
+ | `/cost` | Show usage costs |
23
+ | `/refresh` | Refresh file tree |
24
+ | `/exit` | Exit the CLI |
25
+
26
+ ### Keyboard Shortcuts
27
+
28
+ | Shortcut | Action |
29
+ |----------|--------|
30
+ | `Ctrl+L` | Clear conversation |
31
+ | `Ctrl+T` | Cycle theme |
32
+ | `Ctrl+S` | Save session |
33
+ | `Ctrl+R` | Refresh file tree |
34
+ | `Ctrl+Q` | Quit |
35
+
36
+ ### Input Editing
37
+
38
+ | Shortcut | Action |
39
+ |----------|--------|
40
+ | `Ctrl+C` | Copy selected text |
41
+ | `Ctrl+V` | Paste from clipboard |
42
+ | `Ctrl+A` | Select all text |
43
+ | Click+Drag | Select text |
44
+
45
+ ### Tips:
46
+ - Type any question to chat with the AI
47
+ - Use **Tab** to navigate between panels
48
+ """
49
+
50
+
51
+ def get_models_text() -> str:
52
+ """Get formatted text of available Ollama models."""
53
+ try:
54
+ models = OllamaProvider.get_supported_models()
55
+ if not models:
56
+ return "## Available Models (^^)\n\n*No models found. Is Ollama running?*"
57
+
58
+ lines = [
59
+ "## Available Models (^^)\n",
60
+ "| Model | Status |",
61
+ "|-------|--------|",
62
+ ]
63
+ for model in models:
64
+ lines.append(f"| {model} | (+) Available |")
65
+ lines.append(f"\n*Currently using: **{DEFAULT_MODEL}***")
66
+ return "\n".join(lines)
67
+ except Exception as e:
68
+ return f"## Available Models (^^)\n\n*Error fetching models: {e}*"
@@ -0,0 +1,13 @@
1
+ """Widget exports for Kader CLI."""
2
+
3
+ from .confirmation import InlineSelector, ModelSelector
4
+ from .conversation import ConversationView, Message
5
+ from .loading import LoadingSpinner
6
+
7
+ __all__ = [
8
+ "ConversationView",
9
+ "Message",
10
+ "LoadingSpinner",
11
+ "InlineSelector",
12
+ "ModelSelector",
13
+ ]