kiwi-code 0.0.6__tar.gz → 0.0.7__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 (32) hide show
  1. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/PKG-INFO +1 -1
  2. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/pyproject.toml +1 -1
  3. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/dashboard.py +11 -7
  4. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/widgets.py +91 -1
  5. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/uv.lock +1 -1
  6. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/.github/workflows/publish.yml +0 -0
  7. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/.gitignore +0 -0
  8. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/.python-version +0 -0
  9. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/CLAUDE.md +0 -0
  10. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/Makefile +0 -0
  11. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/README.md +0 -0
  12. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/__init__.py +0 -0
  13. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/auth.py +0 -0
  14. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/cli.py +0 -0
  15. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/client.py +0 -0
  16. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/commands.py +0 -0
  17. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/config.py +0 -0
  18. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/logger.py +0 -0
  19. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/models.py +0 -0
  20. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_cli/runtime_manager.py +0 -0
  21. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_runtime/__init__.py +0 -0
  22. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_runtime/__main__.py +0 -0
  23. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_runtime/main.py +0 -0
  24. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/__init__.py +0 -0
  25. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/main.py +0 -0
  26. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/__init__.py +0 -0
  27. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/actions.py +0 -0
  28. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/autobots.py +0 -0
  29. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/file_browser.py +0 -0
  30. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/login.py +0 -0
  31. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/src/kiwi_tui/screens/runtime_logs.py +0 -0
  32. {kiwi_code-0.0.6 → kiwi_code-0.0.7}/test_hello.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiwi-code
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: A textual-based terminal user interface application
5
5
  Project-URL: Homepage, https://meetkiwi.ai
6
6
  Project-URL: Repository, https://github.com/jetoslabs/kiwi-code
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kiwi-code"
3
- version = "0.0.6"
3
+ version = "0.0.7"
4
4
  description = "A textual-based terminal user interface application"
5
5
  readme = {file = "README.md", content-type = "text/markdown"}
6
6
  requires-python = ">=3.13,<4.0"
@@ -5,6 +5,7 @@ from textual.screen import Screen
5
5
  from textual.widgets import Header, Footer, Input, Static, Button
6
6
  from textual.containers import Vertical, VerticalScroll, Horizontal
7
7
  from kiwi_tui.screens.file_browser import FileBrowserScreen
8
+ from kiwi_tui.widgets import ChatInput
8
9
  from textual.worker import Worker, WorkerState
9
10
  from loguru import logger
10
11
  import json
@@ -166,14 +167,14 @@ class DashboardScreen(Screen):
166
167
  yield Static("", id="pending-files-bar")
167
168
  with Horizontal(id="input-row"):
168
169
  yield Button("+", id="upload-btn", variant="default")
169
- yield Input(placeholder="Message...", id="chat-input")
170
+ yield ChatInput(placeholder="Message...", id="chat-input")
170
171
  yield Button("Send", id="send-btn", variant="default")
171
172
 
172
173
  yield Footer()
173
174
 
174
175
  def on_mount(self) -> None:
175
176
  """Called when screen is mounted."""
176
- self.query_one("#chat-input", Input).focus()
177
+ self.query_one("#chat-input", ChatInput).focus()
177
178
 
178
179
  def on_input_submitted(self, event: Input.Submitted) -> None:
179
180
  """Handle message submission."""
@@ -181,7 +182,9 @@ class DashboardScreen(Screen):
181
182
  if not message:
182
183
  return
183
184
 
184
- # Clear input immediately for responsive feel
185
+ # Record in history and clear input
186
+ chat_input = self.query_one("#chat-input", ChatInput)
187
+ chat_input.record(message)
185
188
  event.input.value = ""
186
189
 
187
190
  # Handle "/" commands
@@ -483,7 +486,7 @@ class DashboardScreen(Screen):
483
486
  for btn_id, label in rows:
484
487
  messages.mount(Button(label, id=btn_id, classes="action-btn"))
485
488
  messages.scroll_end(animate=False)
486
- self.query_one("#chat-input", Input).focus()
489
+ self.query_one("#chat-input", ChatInput).focus()
487
490
 
488
491
  def _render_actions_list(self, command: str, api_client) -> None:
489
492
  """Render /actions list with clickable rows."""
@@ -646,10 +649,11 @@ class DashboardScreen(Screen):
646
649
  return
647
650
 
648
651
  if btn_id == "send-btn":
649
- chat_input = self.query_one("#chat-input", Input)
652
+ chat_input = self.query_one("#chat-input", ChatInput)
650
653
  message = chat_input.value.strip()
651
654
  if not message:
652
655
  return
656
+ chat_input.record(message)
653
657
  chat_input.value = ""
654
658
  if message.startswith("/"):
655
659
  self.handle_slash_command(message)
@@ -709,7 +713,7 @@ class DashboardScreen(Screen):
709
713
  else:
710
714
  return
711
715
 
712
- self.query_one("#chat-input", Input).focus()
716
+ self.query_one("#chat-input", ChatInput).focus()
713
717
 
714
718
  def add_message(self, text: str, msg_type: str = "assistant") -> None:
715
719
  """Add a message to the chat."""
@@ -733,7 +737,7 @@ class DashboardScreen(Screen):
733
737
  self._update_pending_files_bar()
734
738
  else:
735
739
  self.add_message(f"Upload failed: {message}", "error")
736
- self.query_one("#chat-input", Input).focus()
740
+ self.query_one("#chat-input", ChatInput).focus()
737
741
 
738
742
  def _update_pending_files_bar(self) -> None:
739
743
  """Update the pending-files bar to show queued file URLs or hide when empty."""
@@ -2,11 +2,101 @@
2
2
 
3
3
  from textual.app import ComposeResult
4
4
  from textual.containers import Container, Vertical, Horizontal
5
- from textual.widgets import Static, Button, Label, DataTable
5
+ from textual.widgets import Static, Button, Label, DataTable, Input
6
6
  from textual.reactive import reactive
7
+ from textual.suggester import SuggestFromList
7
8
  from rich.text import Text
8
9
 
9
10
 
11
+ # Slash commands for autocomplete
12
+ _SLASH_COMMANDS = [
13
+ "/help",
14
+ "/actions list",
15
+ "/actions get ",
16
+ "/runs list",
17
+ "/runs get ",
18
+ "/graphs list",
19
+ "/graphs get ",
20
+ "/graph-runs list",
21
+ "/graph-runs get ",
22
+ "/use ",
23
+ "/continue ",
24
+ "/new",
25
+ "/status",
26
+ "/cancel",
27
+ "/upload ",
28
+ "/files",
29
+ "/clear-files",
30
+ "/metadata",
31
+ "/metadata set ",
32
+ "/metadata remove ",
33
+ "/metadata clear",
34
+ "/runtime status",
35
+ "/runtime start",
36
+ "/runtime stop",
37
+ "/runtime restart",
38
+ "/runtime list",
39
+ "/runtime logs",
40
+ ]
41
+
42
+
43
+ class ChatInput(Input):
44
+ """Input with command history (up/down arrows) and slash command autocomplete."""
45
+
46
+ _MAX_HISTORY = 200
47
+
48
+ def __init__(self, *args, **kwargs):
49
+ kwargs.setdefault("suggester", SuggestFromList(_SLASH_COMMANDS, case_sensitive=False))
50
+ super().__init__(*args, **kwargs)
51
+ self._history: list[str] = []
52
+ self._history_index: int = -1
53
+ self._draft: str = "" # saves current text when browsing history
54
+
55
+ def record(self, value: str) -> None:
56
+ """Add a submitted value to history."""
57
+ value = value.strip()
58
+ if not value:
59
+ return
60
+ # Deduplicate consecutive
61
+ if self._history and self._history[-1] == value:
62
+ return
63
+ self._history.append(value)
64
+ if len(self._history) > self._MAX_HISTORY:
65
+ self._history.pop(0)
66
+ self._history_index = -1
67
+ self._draft = ""
68
+
69
+ async def _on_key(self, event) -> None:
70
+ if event.key == "up":
71
+ if not self._history:
72
+ return
73
+ event.prevent_default()
74
+ event.stop()
75
+ if self._history_index == -1:
76
+ # Entering history — save current draft
77
+ self._draft = self.value
78
+ self._history_index = len(self._history) - 1
79
+ elif self._history_index > 0:
80
+ self._history_index -= 1
81
+ self.value = self._history[self._history_index]
82
+ self.cursor_position = len(self.value)
83
+ elif event.key == "down":
84
+ if self._history_index == -1:
85
+ return
86
+ event.prevent_default()
87
+ event.stop()
88
+ if self._history_index < len(self._history) - 1:
89
+ self._history_index += 1
90
+ self.value = self._history[self._history_index]
91
+ else:
92
+ # Past end — restore draft
93
+ self._history_index = -1
94
+ self.value = self._draft
95
+ self.cursor_position = len(self.value)
96
+ else:
97
+ await super()._on_key(event)
98
+
99
+
10
100
  class StatusBadge(Static):
11
101
  """A colored status badge widget."""
12
102
 
@@ -319,7 +319,7 @@ wheels = [
319
319
 
320
320
  [[package]]
321
321
  name = "kiwi-code"
322
- version = "0.0.6"
322
+ version = "0.0.7"
323
323
  source = { editable = "." }
324
324
  dependencies = [
325
325
  { name = "autobots-client" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes