kader 0.1.4__tar.gz → 0.1.5__tar.gz

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 (78) hide show
  1. {kader-0.1.4 → kader-0.1.5}/PKG-INFO +1 -1
  2. {kader-0.1.4 → kader-0.1.5}/cli/app.py +59 -25
  3. {kader-0.1.4 → kader-0.1.5}/cli/app.tcss +9 -10
  4. {kader-0.1.4 → kader-0.1.5}/cli/utils.py +13 -8
  5. {kader-0.1.4 → kader-0.1.5}/cli/widgets/confirmation.py +5 -5
  6. {kader-0.1.4 → kader-0.1.5}/cli/widgets/conversation.py +1 -1
  7. {kader-0.1.4 → kader-0.1.5}/cli/widgets/loading.py +1 -1
  8. {kader-0.1.4 → kader-0.1.5}/pyproject.toml +1 -1
  9. {kader-0.1.4 → kader-0.1.5}/uv.lock +1 -1
  10. {kader-0.1.4 → kader-0.1.5}/.github/workflows/ci.yml +0 -0
  11. {kader-0.1.4 → kader-0.1.5}/.github/workflows/release.yml +0 -0
  12. {kader-0.1.4 → kader-0.1.5}/.gitignore +0 -0
  13. {kader-0.1.4 → kader-0.1.5}/.python-version +0 -0
  14. {kader-0.1.4 → kader-0.1.5}/.qwen/QWEN.md +0 -0
  15. {kader-0.1.4 → kader-0.1.5}/.qwen/agents/technical-writer.md +0 -0
  16. {kader-0.1.4 → kader-0.1.5}/.qwen/agents/test-automation-specialist.md +0 -0
  17. {kader-0.1.4 → kader-0.1.5}/README.md +0 -0
  18. {kader-0.1.4 → kader-0.1.5}/cli/README.md +0 -0
  19. {kader-0.1.4 → kader-0.1.5}/cli/__init__.py +0 -0
  20. {kader-0.1.4 → kader-0.1.5}/cli/__main__.py +0 -0
  21. {kader-0.1.4 → kader-0.1.5}/cli/widgets/__init__.py +0 -0
  22. {kader-0.1.4 → kader-0.1.5}/examples/.gitignore +0 -0
  23. {kader-0.1.4 → kader-0.1.5}/examples/README.md +0 -0
  24. {kader-0.1.4 → kader-0.1.5}/examples/memory_example.py +0 -0
  25. {kader-0.1.4 → kader-0.1.5}/examples/ollama_example.py +0 -0
  26. {kader-0.1.4 → kader-0.1.5}/examples/planning_agent_example.py +0 -0
  27. {kader-0.1.4 → kader-0.1.5}/examples/python_developer/main.py +0 -0
  28. {kader-0.1.4 → kader-0.1.5}/examples/python_developer/template.yaml +0 -0
  29. {kader-0.1.4 → kader-0.1.5}/examples/react_agent_example.py +0 -0
  30. {kader-0.1.4 → kader-0.1.5}/examples/simple_agent.py +0 -0
  31. {kader-0.1.4 → kader-0.1.5}/examples/todo_agent/main.py +0 -0
  32. {kader-0.1.4 → kader-0.1.5}/examples/tools_example.py +0 -0
  33. {kader-0.1.4 → kader-0.1.5}/kader/__init__.py +0 -0
  34. {kader-0.1.4 → kader-0.1.5}/kader/agent/__init__.py +0 -0
  35. {kader-0.1.4 → kader-0.1.5}/kader/agent/agents.py +0 -0
  36. {kader-0.1.4 → kader-0.1.5}/kader/agent/base.py +0 -0
  37. {kader-0.1.4 → kader-0.1.5}/kader/agent/logger.py +0 -0
  38. {kader-0.1.4 → kader-0.1.5}/kader/config.py +0 -0
  39. {kader-0.1.4 → kader-0.1.5}/kader/memory/__init__.py +0 -0
  40. {kader-0.1.4 → kader-0.1.5}/kader/memory/conversation.py +0 -0
  41. {kader-0.1.4 → kader-0.1.5}/kader/memory/session.py +0 -0
  42. {kader-0.1.4 → kader-0.1.5}/kader/memory/state.py +0 -0
  43. {kader-0.1.4 → kader-0.1.5}/kader/memory/types.py +0 -0
  44. {kader-0.1.4 → kader-0.1.5}/kader/prompts/__init__.py +0 -0
  45. {kader-0.1.4 → kader-0.1.5}/kader/prompts/agent_prompts.py +0 -0
  46. {kader-0.1.4 → kader-0.1.5}/kader/prompts/base.py +0 -0
  47. {kader-0.1.4 → kader-0.1.5}/kader/prompts/templates/planning_agent.j2 +0 -0
  48. {kader-0.1.4 → kader-0.1.5}/kader/prompts/templates/react_agent.j2 +0 -0
  49. {kader-0.1.4 → kader-0.1.5}/kader/providers/__init__.py +0 -0
  50. {kader-0.1.4 → kader-0.1.5}/kader/providers/base.py +0 -0
  51. {kader-0.1.4 → kader-0.1.5}/kader/providers/mock.py +0 -0
  52. {kader-0.1.4 → kader-0.1.5}/kader/providers/ollama.py +0 -0
  53. {kader-0.1.4 → kader-0.1.5}/kader/tools/README.md +0 -0
  54. {kader-0.1.4 → kader-0.1.5}/kader/tools/__init__.py +0 -0
  55. {kader-0.1.4 → kader-0.1.5}/kader/tools/base.py +0 -0
  56. {kader-0.1.4 → kader-0.1.5}/kader/tools/exec_commands.py +0 -0
  57. {kader-0.1.4 → kader-0.1.5}/kader/tools/filesys.py +0 -0
  58. {kader-0.1.4 → kader-0.1.5}/kader/tools/filesystem.py +0 -0
  59. {kader-0.1.4 → kader-0.1.5}/kader/tools/protocol.py +0 -0
  60. {kader-0.1.4 → kader-0.1.5}/kader/tools/rag.py +0 -0
  61. {kader-0.1.4 → kader-0.1.5}/kader/tools/todo.py +0 -0
  62. {kader-0.1.4 → kader-0.1.5}/kader/tools/utils.py +0 -0
  63. {kader-0.1.4 → kader-0.1.5}/kader/tools/web.py +0 -0
  64. {kader-0.1.4 → kader-0.1.5}/tests/conftest.py +0 -0
  65. {kader-0.1.4 → kader-0.1.5}/tests/providers/test_mock.py +0 -0
  66. {kader-0.1.4 → kader-0.1.5}/tests/providers/test_ollama.py +0 -0
  67. {kader-0.1.4 → kader-0.1.5}/tests/providers/test_providers_base.py +0 -0
  68. {kader-0.1.4 → kader-0.1.5}/tests/test_agent_logger.py +0 -0
  69. {kader-0.1.4 → kader-0.1.5}/tests/test_agent_logger_integration.py +0 -0
  70. {kader-0.1.4 → kader-0.1.5}/tests/test_base_agent.py +0 -0
  71. {kader-0.1.4 → kader-0.1.5}/tests/test_file_memory.py +0 -0
  72. {kader-0.1.4 → kader-0.1.5}/tests/test_todo_tool.py +0 -0
  73. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_exec_commands.py +0 -0
  74. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_filesys_tools.py +0 -0
  75. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_filesystem_tools.py +0 -0
  76. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_rag.py +0 -0
  77. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_tools_base.py +0 -0
  78. {kader-0.1.4 → kader-0.1.5}/tests/tools/test_web.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kader
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: kader coding agent
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: faiss-cpu>=1.9.0
@@ -10,12 +10,12 @@ from textual.app import App, ComposeResult
10
10
  from textual.binding import Binding
11
11
  from textual.containers import Container, Horizontal, Vertical
12
12
  from textual.widgets import (
13
- DirectoryTree,
14
13
  Footer,
15
14
  Header,
16
15
  Input,
17
16
  Markdown,
18
17
  Static,
18
+ Tree,
19
19
  )
20
20
 
21
21
  from kader.agent.agents import ReActAgent
@@ -66,11 +66,18 @@ MIN_WIDTH = 89
66
66
  MIN_HEIGHT = 29
67
67
 
68
68
 
69
+ class ASCIITree(Tree):
70
+ """A Tree widget that uses no icons."""
71
+
72
+ ICON_NODE = ""
73
+ ICON_NODE_EXPANDED = ""
74
+
75
+
69
76
  class KaderApp(App):
70
77
  """Main Kader CLI application."""
71
78
 
72
79
  TITLE = "Kader CLI"
73
- SUB_TITLE = "Modern Vibe Coding Assistant"
80
+ SUB_TITLE = f"v{get_version('kader')}"
74
81
  CSS_PATH = "app.tcss"
75
82
 
76
83
  BINDINGS = [
@@ -180,7 +187,7 @@ class KaderApp(App):
180
187
  if event.confirmed:
181
188
  if tool_message:
182
189
  conversation.add_message(tool_message, "assistant")
183
- conversation.add_message(" Executing tool...", "assistant")
190
+ conversation.add_message("(+) Executing tool...", "assistant")
184
191
  # Restart spinner
185
192
  try:
186
193
  spinner = self.query_one(LoadingSpinner)
@@ -188,7 +195,7 @@ class KaderApp(App):
188
195
  except Exception:
189
196
  pass
190
197
  else:
191
- conversation.add_message(" Tool execution skipped.", "assistant")
198
+ conversation.add_message("(-) Tool execution skipped.", "assistant")
192
199
 
193
200
  # Re-enable input
194
201
  prompt_input = self.query_one("#prompt-input", Input)
@@ -210,7 +217,8 @@ class KaderApp(App):
210
217
  models = OllamaProvider.get_supported_models()
211
218
  if not models:
212
219
  conversation.add_message(
213
- "## Models 🤖\n\n*No models found. Is Ollama running?*", "assistant"
220
+ "## Models (^^)\n\n*No models found. Is Ollama running?*",
221
+ "assistant",
214
222
  )
215
223
  return
216
224
 
@@ -228,7 +236,7 @@ class KaderApp(App):
228
236
 
229
237
  except Exception as e:
230
238
  conversation.add_message(
231
- f"## Models 🤖\n\n*Error fetching models: {e}*", "assistant"
239
+ f"## Models (^^)\n\n*Error fetching models: {e}*", "assistant"
232
240
  )
233
241
 
234
242
  def on_model_selector_model_selected(
@@ -248,7 +256,7 @@ class KaderApp(App):
248
256
  self._agent = self._create_agent(self._current_model)
249
257
 
250
258
  conversation.add_message(
251
- f" Model changed from `{old_model}` to `{self._current_model}`",
259
+ f"(+) Model changed from `{old_model}` to `{self._current_model}`",
252
260
  "assistant",
253
261
  )
254
262
 
@@ -285,8 +293,8 @@ class KaderApp(App):
285
293
  with Horizontal(id="main-container"):
286
294
  # Sidebar with directory tree
287
295
  with Vertical(id="sidebar"):
288
- yield Static("📁 Files", id="sidebar-title")
289
- yield DirectoryTree(Path.cwd(), id="directory-tree")
296
+ yield Static("Files", id="sidebar-title")
297
+ yield ASCIITree(str(Path.cwd().name), id="directory-tree")
290
298
 
291
299
  # Main content area
292
300
  with Vertical(id="content-area"):
@@ -316,9 +324,32 @@ class KaderApp(App):
316
324
  # Check initial size
317
325
  self._check_terminal_size()
318
326
 
327
+ # Start background update check
319
328
  # Start background update check
320
329
  threading.Thread(target=self._check_for_updates, daemon=True).start()
321
330
 
331
+ # Initial tree population
332
+ self._refresh_directory_tree()
333
+
334
+ def _populate_tree(self, node, path: Path) -> None:
335
+ """Recursively populate the tree with ASCII symbols."""
336
+ try:
337
+ # Sort: directories first, then files
338
+ items = sorted(
339
+ path.iterdir(), key=lambda p: (not p.is_dir(), p.name.lower())
340
+ )
341
+ for child in items:
342
+ if child.name.startswith((".", "__pycache__")):
343
+ continue
344
+
345
+ if child.is_dir():
346
+ new_node = node.add(f"[+] {child.name}", expand=False)
347
+ self._populate_tree(new_node, child)
348
+ else:
349
+ node.add(f"{child.name}")
350
+ except Exception:
351
+ pass
352
+
322
353
  def _check_for_updates(self) -> None:
323
354
  """Check for package updates in background thread."""
324
355
  try:
@@ -369,7 +400,7 @@ class KaderApp(App):
369
400
  except Exception:
370
401
  if too_small:
371
402
  # Show warning overlay
372
- warning_text = f"""⚠️ Terminal Too Small
403
+ warning_text = f"""<!> Terminal Too Small
373
404
 
374
405
  Current: {width}x{height}
375
406
  Minimum: {MIN_WIDTH}x{MIN_HEIGHT}
@@ -406,7 +437,7 @@ Please resize your terminal."""
406
437
  self._cycle_theme()
407
438
  theme_name = THEME_NAMES[self._current_theme_index]
408
439
  conversation.add_message(
409
- f"🎨 Theme changed to **{theme_name}**!", "assistant"
440
+ f"{{~}} Theme changed to **{theme_name}**!", "assistant"
410
441
  )
411
442
  elif cmd == "/clear":
412
443
  conversation.clear_messages()
@@ -482,7 +513,7 @@ Please resize your terminal."""
482
513
 
483
514
  except Exception as e:
484
515
  spinner.stop()
485
- error_msg = f" **Error:** {str(e)}\n\nMake sure Ollama is running and the model `{self._current_model}` is available."
516
+ error_msg = f"(-) **Error:** {str(e)}\n\nMake sure Ollama is running and the model `{self._current_model}` is available."
486
517
  conversation.add_message(error_msg, "assistant")
487
518
  self.notify(f"Error: {e}", severity="error")
488
519
 
@@ -530,10 +561,13 @@ Please resize your terminal."""
530
561
  self.notify("Directory tree refreshed!", severity="information")
531
562
 
532
563
  def _refresh_directory_tree(self) -> None:
533
- """Refresh the directory tree to show new/modified files."""
564
+ """Refresh the directory tree with ASCII symbols."""
534
565
  try:
535
- tree = self.query_one("#directory-tree", DirectoryTree)
536
- tree.reload()
566
+ tree = self.query_one("#directory-tree", ASCIITree)
567
+ tree.clear()
568
+ tree.root.label = str(Path.cwd().name)
569
+ self._populate_tree(tree.root, Path.cwd())
570
+ tree.root.expand()
537
571
  except Exception:
538
572
  pass # Silently ignore if tree not found
539
573
 
@@ -550,12 +584,12 @@ Please resize your terminal."""
550
584
  self._session_manager.save_conversation(self._current_session_id, messages)
551
585
 
552
586
  conversation.add_message(
553
- f" Session saved!\n\n**Session ID:** `{self._current_session_id}`",
587
+ f"(+) Session saved!\n\n**Session ID:** `{self._current_session_id}`",
554
588
  "assistant",
555
589
  )
556
590
  self.notify("Session saved!", severity="information")
557
591
  except Exception as e:
558
- conversation.add_message(f" Error saving session: {e}", "assistant")
592
+ conversation.add_message(f"(-) Error saving session: {e}", "assistant")
559
593
  self.notify(f"Error: {e}", severity="error")
560
594
 
561
595
  def _handle_load_session(
@@ -567,7 +601,7 @@ Please resize your terminal."""
567
601
  session = self._session_manager.get_session(session_id)
568
602
  if not session:
569
603
  conversation.add_message(
570
- f" Session `{session_id}` not found.\n\nUse `/sessions` to see available sessions.",
604
+ f"(-) Session `{session_id}` not found.\n\nUse `/sessions` to see available sessions.",
571
605
  "assistant",
572
606
  )
573
607
  return
@@ -589,12 +623,12 @@ Please resize your terminal."""
589
623
 
590
624
  self._current_session_id = session_id
591
625
  conversation.add_message(
592
- f" Session `{session_id}` loaded with {len(messages)} messages.",
626
+ f"(+) Session `{session_id}` loaded with {len(messages)} messages.",
593
627
  "assistant",
594
628
  )
595
629
  self.notify("Session loaded!", severity="information")
596
630
  except Exception as e:
597
- conversation.add_message(f" Error loading session: {e}", "assistant")
631
+ conversation.add_message(f"(-) Error loading session: {e}", "assistant")
598
632
  self.notify(f"Error: {e}", severity="error")
599
633
 
600
634
  def _handle_list_sessions(self, conversation: ConversationView) -> None:
@@ -604,13 +638,13 @@ Please resize your terminal."""
604
638
 
605
639
  if not sessions:
606
640
  conversation.add_message(
607
- "📭 No saved sessions found.\n\nUse `/save` to save the current session.",
641
+ "[ ] No saved sessions found.\n\nUse `/save` to save the current session.",
608
642
  "assistant",
609
643
  )
610
644
  return
611
645
 
612
646
  lines = [
613
- "## Saved Sessions 📂\n",
647
+ "## Saved Sessions [=]\n",
614
648
  "| Session ID | Created | Updated |",
615
649
  "|------------|---------|---------|",
616
650
  ]
@@ -635,7 +669,7 @@ Please resize your terminal."""
635
669
  model = self._agent.provider.model
636
670
 
637
671
  lines = [
638
- "## Usage Costs 💰\n",
672
+ "## Usage Costs ($)\n",
639
673
  f"**Model:** `{model}`\n",
640
674
  "### Cost Breakdown",
641
675
  "| Type | Amount |",
@@ -654,12 +688,12 @@ Please resize your terminal."""
654
688
 
655
689
  if cost.total_cost == 0.0:
656
690
  lines.append(
657
- "\n> 💡 *Note: Ollama runs locally, so there are no API costs.*"
691
+ "\n> (!) *Note: Ollama runs locally, so there are no API costs.*"
658
692
  )
659
693
 
660
694
  conversation.add_message("\n".join(lines), "assistant")
661
695
  except Exception as e:
662
- conversation.add_message(f" Error getting costs: {e}", "assistant")
696
+ conversation.add_message(f"(-) Error getting costs: {e}", "assistant")
663
697
  self.notify(f"Error: {e}", severity="error")
664
698
 
665
699
 
@@ -42,7 +42,7 @@ Header {
42
42
  background: $primary;
43
43
  color: $text;
44
44
  text-style: bold;
45
- height: 3;
45
+ height: 1;
46
46
  dock: top;
47
47
  }
48
48
 
@@ -75,9 +75,9 @@ FooterKey > .footer-key--key {
75
75
  /* ===== Sidebar (Directory Tree) ===== */
76
76
 
77
77
  #sidebar {
78
- width: 30;
79
- min-width: 20;
80
- max-width: 50;
78
+ width: 22;
79
+ min-width: 18;
80
+ max-width: 35;
81
81
  background: $surface;
82
82
  border-right: thick $primary;
83
83
  padding: 0;
@@ -126,7 +126,6 @@ DirectoryTree:focus > .directory-tree--cursor {
126
126
  #conversation {
127
127
  height: 1fr;
128
128
  background: $background;
129
- border-bottom: thick $surface;
130
129
  }
131
130
 
132
131
  ConversationView {
@@ -148,15 +147,15 @@ ConversationView {
148
147
 
149
148
  #input-container {
150
149
  height: auto;
151
- min-height: 3;
152
- max-height: 5;
153
- background: $surface;
150
+ min-height: 4;
151
+ max-height: 7;
152
+ background: $background;
154
153
  padding: 1;
155
- border-top: thick $primary;
154
+ margin-bottom: 1;
156
155
  }
157
156
 
158
157
  #prompt-input {
159
- background: $background;
158
+ background: transparent;
160
159
  border: round $primary;
161
160
  padding: 0 1;
162
161
  height: 3;
@@ -8,7 +8,7 @@ THEME_NAMES = ["dark", "ocean", "forest", "sunset"]
8
8
  # Default model
9
9
  DEFAULT_MODEL = "qwen3-coder:480b-cloud"
10
10
 
11
- HELP_TEXT = """## Kader CLI Commands 📖
11
+ HELP_TEXT = """## Kader CLI Commands
12
12
 
13
13
  | Command | Description |
14
14
  |---------|-------------|
@@ -23,7 +23,7 @@ HELP_TEXT = """## Kader CLI Commands 📖
23
23
  | `/refresh` | Refresh file tree |
24
24
  | `/exit` | Exit the CLI |
25
25
 
26
- ### Keyboard Shortcuts ⌨️
26
+ ### Keyboard Shortcuts
27
27
 
28
28
  | Shortcut | Action |
29
29
  |----------|--------|
@@ -33,7 +33,7 @@ HELP_TEXT = """## Kader CLI Commands 📖
33
33
  | `Ctrl+R` | Refresh file tree |
34
34
  | `Ctrl+Q` | Quit |
35
35
 
36
- ### Input Editing 📝
36
+ ### Input Editing
37
37
 
38
38
  | Shortcut | Action |
39
39
  |----------|--------|
@@ -44,7 +44,8 @@ HELP_TEXT = """## Kader CLI Commands 📖
44
44
 
45
45
  ### Tips:
46
46
  - Type any question to chat with the AI
47
- - Use **Tab** to navigate between panels"""
47
+ - Use **Tab** to navigate between panels
48
+ """
48
49
 
49
50
 
50
51
  def get_models_text() -> str:
@@ -52,12 +53,16 @@ def get_models_text() -> str:
52
53
  try:
53
54
  models = OllamaProvider.get_supported_models()
54
55
  if not models:
55
- return "## Available Models 🤖\n\n*No models found. Is Ollama running?*"
56
+ return "## Available Models (^^)\n\n*No models found. Is Ollama running?*"
56
57
 
57
- lines = ["## Available Models 🤖\n", "| Model | Status |", "|-------|--------|"]
58
+ lines = [
59
+ "## Available Models (^^)\n",
60
+ "| Model | Status |",
61
+ "|-------|--------|",
62
+ ]
58
63
  for model in models:
59
- lines.append(f"| {model} | Available |")
64
+ lines.append(f"| {model} | (+) Available |")
60
65
  lines.append(f"\n*Currently using: **{DEFAULT_MODEL}***")
61
66
  return "\n".join(lines)
62
67
  except Exception as e:
63
- return f"## Available Models 🤖\n\n*Error fetching models: {e}*"
68
+ return f"## Available Models (^^)\n\n*Error fetching models: {e}*"
@@ -84,12 +84,12 @@ class InlineSelector(Widget, can_focus=True):
84
84
  def __init__(self, message: str, options: list[str] = None, **kwargs) -> None:
85
85
  super().__init__(**kwargs)
86
86
  self.message = message
87
- self.options = options or [" Yes", " No"]
87
+ self.options = options or ["(+) Yes", "(-) No"]
88
88
 
89
89
  def compose(self) -> ComposeResult:
90
90
  from textual.containers import Horizontal
91
91
 
92
- yield Static(f"🔧 {self.message}", classes="message-text")
92
+ yield Static(f">_ {self.message}", classes="message-text")
93
93
  yield Static(
94
94
  "↑↓ to select • Enter to confirm • Y/N for quick select",
95
95
  classes="prompt-text",
@@ -230,7 +230,7 @@ class ModelSelector(Widget, can_focus=True):
230
230
  self.selected_index = models.index(current_model)
231
231
 
232
232
  def compose(self) -> ComposeResult:
233
- yield Static("🤖 Select Model", classes="title-text")
233
+ yield Static("(^^) Select Model", classes="title-text")
234
234
  yield Static(
235
235
  "↑↓ to navigate • Enter to select • Esc to cancel", classes="prompt-text"
236
236
  )
@@ -245,7 +245,7 @@ class ModelSelector(Widget, can_focus=True):
245
245
  classes += " not-selected"
246
246
  if is_current:
247
247
  classes += " current"
248
- label = f" {model}" if is_selected else f" {model}"
248
+ label = f" >> {model}" if is_selected else f" {model}"
249
249
  if is_current:
250
250
  label += " (current)"
251
251
  yield Static(label, classes=classes, id=f"model-{i}")
@@ -272,7 +272,7 @@ class ModelSelector(Widget, can_focus=True):
272
272
  new_option.remove_class("not-selected")
273
273
  new_option.add_class("selected")
274
274
  new_model = self.models[new_index]
275
- new_label = f" {new_model}"
275
+ new_label = f" >> {new_model}"
276
276
  if new_model == self.current_model:
277
277
  new_label += " (current)"
278
278
  new_option.update(new_label)
@@ -15,7 +15,7 @@ class Message(Static):
15
15
  self.add_class(f"message-{role}")
16
16
 
17
17
  def compose(self) -> ComposeResult:
18
- prefix = "👤 **You:**" if self.role == "user" else "🤖 **Kader:**"
18
+ prefix = "(**) **You:**" if self.role == "user" else "(^^) **Kader:**"
19
19
  yield Markdown(f"{prefix}\n\n{self.content}")
20
20
 
21
21
 
@@ -21,7 +21,7 @@ class LoadingSpinner(Static):
21
21
  }
22
22
  """
23
23
 
24
- SPINNER_FRAMES = ["", "", "⠹", "⠸", "⠼", "⠴", "", "", "", "⠏"]
24
+ SPINNER_FRAMES = ["= ", "== ", "=== ", " ===", " ==", " =", " "]
25
25
 
26
26
  frame_index: reactive[int] = reactive(0)
27
27
  is_spinning: reactive[bool] = reactive(False)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kader"
3
- version = "0.1.4"
3
+ version = "0.1.5"
4
4
  description = "kader coding agent"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -487,7 +487,7 @@ wheels = [
487
487
 
488
488
  [[package]]
489
489
  name = "kader"
490
- version = "0.1.4"
490
+ version = "0.1.5"
491
491
  source = { editable = "." }
492
492
  dependencies = [
493
493
  { name = "faiss-cpu" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes