cobalt-cli-linux 0.1.2__tar.gz → 0.1.3__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 (22) hide show
  1. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/PKG-INFO +1 -1
  2. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/pyproject.toml +1 -1
  3. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/tui.py +31 -31
  4. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/PKG-INFO +1 -1
  5. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/tests/test_cli.py +6 -0
  6. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/README.md +0 -0
  7. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/setup.cfg +0 -0
  8. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/ASCII.txt +0 -0
  9. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/__init__.py +0 -0
  10. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/__main__.py +0 -0
  11. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/agent.py +0 -0
  12. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/cli.py +0 -0
  13. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/config.py +0 -0
  14. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/deepseek_client.py +0 -0
  15. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/executor.py +0 -0
  16. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/groq_client.py +0 -0
  17. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux/history.py +0 -0
  18. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/SOURCES.txt +0 -0
  19. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/dependency_links.txt +0 -0
  20. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/entry_points.txt +0 -0
  21. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/requires.txt +0 -0
  22. {cobalt_cli_linux-0.1.2 → cobalt_cli_linux-0.1.3}/src/cobalt_cli_linux.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cobalt-cli-linux
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Agentic Groq-powered CLI assistant for Debian Linux
5
5
  Author: Cobalt
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cobalt-cli-linux"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Agentic Groq-powered CLI assistant for Debian Linux"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -8,6 +8,14 @@ from pathlib import Path
8
8
  from .agent import CobaltAgent
9
9
  from .history import ChatStore
10
10
 
11
+ COBALT_CLI_ART = (
12
+ " ____ ___ ____ _ _ _____ ____ _ ___ ",
13
+ " / ___/ _ \\| __ ) / \\ | | |_ _| / ___| | |_ _|",
14
+ " | | | | | | _ \\ / _ \\ | | | | | | | | | | ",
15
+ " | |__| |_| | |_) / ___ \\| |___| | | |___| |___ | | ",
16
+ " \\____\\___/|____/_/ \\_\\_____|_| \\____|_____|___|",
17
+ )
18
+
11
19
 
12
20
  class CobaltTUI:
13
21
  def __init__(self, settings) -> None:
@@ -22,17 +30,8 @@ class CobaltTUI:
22
30
  self.current_chat = self.chat_store.load_chat(self.selected_chat_path)
23
31
  self.history = self.current_chat
24
32
  self.saved_chats = self.chat_files
25
- self.ascii_lines = self._load_ascii_art()
26
33
  self.input_focused = True
27
34
 
28
- def _load_ascii_art(self) -> list[str]:
29
- ascii_path = Path(__file__).with_name("ASCII.txt")
30
- if not ascii_path.exists():
31
- ascii_path = Path(__file__).resolve().parents[2] / "ASCII.txt"
32
- if not ascii_path.exists():
33
- return ["COBALT"]
34
- return [line.rstrip() for line in ascii_path.read_text(encoding="utf-8").splitlines() if line.strip()]
35
-
36
35
  def _refresh_chat_files(self) -> None:
37
36
  self.chat_files = self.chat_store.list_chats()
38
37
  if not self.chat_files:
@@ -124,8 +123,12 @@ class CobaltTUI:
124
123
 
125
124
  sidebar_w = min(26, max(20, width // 4))
126
125
  sidebar_x = 1
127
- sidebar_y = 1
128
- sidebar_h = max(8, height - 4)
126
+ for index, line in enumerate(COBALT_CLI_ART):
127
+ x = max(0, (width - len(line)) // 2)
128
+ stdscr.addstr(index, x, line[: max(0, width - x)])
129
+
130
+ sidebar_y = 6
131
+ sidebar_h = max(8, height - 9)
129
132
  self._draw_box(stdscr, sidebar_y, sidebar_x, sidebar_h, sidebar_w, " Chats ")
130
133
 
131
134
  chat_files = self.chat_store.list_chats()[-8:]
@@ -143,20 +146,12 @@ class CobaltTUI:
143
146
 
144
147
  main_x = sidebar_x + sidebar_w + 2
145
148
  main_w = max(20, width - main_x - 2)
146
- main_y = 1
147
- main_h = max(8, height - 4)
149
+ main_y = 6
150
+ main_h = max(8, height - 9)
148
151
  self._draw_box(stdscr, main_y, main_x, main_h, main_w, f" {self.history.title or 'conversation'} ")
149
152
 
150
153
  box_x, box_y, box_width, box_height, input_lines = self._input_box_geometry(main_x, main_y, main_w, main_h, input_text)
151
- if not self.history.messages:
152
- content_height = max(1, box_y - main_y - 1)
153
- art_start = main_y + max(1, (content_height - len(self.ascii_lines)) // 2)
154
- for idx, line in enumerate(self.ascii_lines):
155
- y = art_start + idx
156
- x = main_x + max(0, (main_w - len(line)) // 2)
157
- if y < box_y:
158
- stdscr.addstr(y, x, line[: max(0, main_w - 2)])
159
- else:
154
+ if self.history.messages:
160
155
  rows: list[str] = []
161
156
  for message in self.history.latest(18):
162
157
  role = message.get("role", "user").upper()
@@ -195,17 +190,22 @@ class CobaltTUI:
195
190
 
196
191
  agent = CobaltAgent(settings=self.settings)
197
192
  agent.history = self.history
198
- agent.process_stream(input_text.strip(), on_chunk=on_chunk)
193
+ response = agent.process_stream(input_text.strip(), on_chunk=on_chunk)
199
194
  self.history = agent.history
200
195
  self.current_chat = self.history
201
196
  self.saved_chats = self.chat_store.list_chats()
197
+ if response and not buffer:
198
+ buffer = response
199
+ if not buffer:
200
+ raise RuntimeError("The assistant returned an empty response")
201
+ self._render(stdscr, "", "")
202
202
  return buffer
203
203
 
204
204
  def _handle_mouse_click(self, x: int, y: int) -> bool:
205
205
  sidebar_w = min(26, max(20, curses.COLS // 4))
206
206
  sidebar_x = 1
207
- sidebar_y = 1
208
- sidebar_h = max(8, curses.LINES - 4)
207
+ sidebar_y = 6
208
+ sidebar_h = max(8, curses.LINES - 9)
209
209
 
210
210
  if sidebar_x <= x < sidebar_x + sidebar_w and sidebar_y <= y < sidebar_y + sidebar_h:
211
211
  chat_files = self.chat_store.list_chats()[-8:]
@@ -224,9 +224,9 @@ class CobaltTUI:
224
224
  height, width = curses.LINES, curses.COLS
225
225
  sidebar_w = min(26, max(20, width // 4))
226
226
  main_x = 3 + sidebar_w
227
- main_y = 1
227
+ main_y = 6
228
228
  main_w = max(20, width - main_x - 2)
229
- main_h = max(8, height - 4)
229
+ main_h = max(8, height - 9)
230
230
  box_x, box_y, box_width, box_height, _ = self._input_box_geometry(main_x, main_y, main_w, main_h, input_text)
231
231
  return box_x <= x < box_x + box_width and box_y <= y < box_y + box_height
232
232
 
@@ -255,7 +255,7 @@ class CobaltTUI:
255
255
  self.input_focused = True
256
256
  continue
257
257
  if button_state & (curses.BUTTON1_PRESSED | curses.BUTTON1_CLICKED | curses.BUTTON1_RELEASED) and self._handle_mouse_click(x, y):
258
- status = "Chat selected"
258
+ status = ""
259
259
  input_text = ""
260
260
  self.input_focused = False
261
261
  continue
@@ -273,7 +273,7 @@ class CobaltTUI:
273
273
  self.selected_chat_path = str(self.current_chat.path)
274
274
  self.chat_files = self.chat_store.list_chats()
275
275
  input_text = ""
276
- status = "New chat started"
276
+ status = ""
277
277
  continue
278
278
 
279
279
  if ch in (4, ord("d")) and self.selected_chat_path:
@@ -290,7 +290,7 @@ class CobaltTUI:
290
290
  self.history = self.current_chat
291
291
  self.selected_chat_path = str(self.current_chat.path)
292
292
  input_text = ""
293
- status = "Chat deleted"
293
+ status = ""
294
294
  continue
295
295
  if ch in (10, 13, curses.KEY_ENTER):
296
296
  if input_text.strip():
@@ -299,7 +299,7 @@ class CobaltTUI:
299
299
  self.history.title = self._suggest_chat_title(input_text.strip())
300
300
  self.history.save()
301
301
  self._stream_response(stdscr, input_text)
302
- status = "Response received"
302
+ status = ""
303
303
  except (OSError, RuntimeError, ValueError) as exc:
304
304
  self.history.add("assistant", f"Error: {exc}")
305
305
  status = ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cobalt-cli-linux
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Agentic Groq-powered CLI assistant for Debian Linux
5
5
  Author: Cobalt
6
6
  License-Expression: MIT
@@ -126,6 +126,12 @@ def test_stream_error_reads_response_before_inspecting_body(monkeypatch) -> None
126
126
  raise AssertionError("Expected streamed API error")
127
127
 
128
128
 
129
+ def test_tui_empty_chat_does_not_load_prompt_art_as_body_content(tmp_path: Path) -> None:
130
+ tui = CobaltTUI(settings=Settings())
131
+
132
+ assert not hasattr(tui, "ascii_lines")
133
+
134
+
129
135
  def test_write_file_tool_creates_and_verifies_file(tmp_path: Path) -> None:
130
136
  agent = CobaltAgent(settings=Settings(), history=ConversationHistory(tmp_path / "history.json"))
131
137
  target = tmp_path / "test.txt"