claude-sdk-tutor 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.
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/PKG-INFO +2 -1
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/app.py +7 -2
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/pyproject.toml +2 -1
- claude_sdk_tutor-0.1.5/src/claude/__init__.py +4 -0
- claude_sdk_tutor-0.1.5/src/claude/history.py +73 -0
- claude_sdk_tutor-0.1.5/src/claude/widgets.py +27 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/uv.lock +3 -1
- claude_sdk_tutor-0.1.4/src/claude/__init__.py +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/.gitignore +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/.python-version +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/CLAUDE.md +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/LICENSE +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/Makefile +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/README.md +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/__init__.py +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/src/__init__.py +0 -0
- {claude_sdk_tutor-0.1.4 → claude_sdk_tutor-0.1.5}/src/claude/claude_agent.py +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-sdk-tutor
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.13
|
|
7
7
|
Requires-Dist: claude-agent-sdk>=0.1.26
|
|
8
|
+
Requires-Dist: platformdirs>=4.0.0
|
|
8
9
|
Requires-Dist: textual-dev>=1.8.0
|
|
9
10
|
Requires-Dist: textual>=7.5.0
|
|
10
11
|
Requires-Dist: watchfiles>=1.1.1
|
|
@@ -12,6 +12,8 @@ from claude.claude_agent import (
|
|
|
12
12
|
create_claude_client,
|
|
13
13
|
stream_helpful_claude,
|
|
14
14
|
)
|
|
15
|
+
from claude.history import CommandHistory
|
|
16
|
+
from claude.widgets import HistoryInput
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class MyApp(App):
|
|
@@ -22,6 +24,7 @@ class MyApp(App):
|
|
|
22
24
|
self.client = create_claude_client(
|
|
23
25
|
tutor_mode=self.tutor_mode, web_search=self.web_search_enabled
|
|
24
26
|
)
|
|
27
|
+
self.history = CommandHistory()
|
|
25
28
|
|
|
26
29
|
CSS = """
|
|
27
30
|
#main {
|
|
@@ -59,7 +62,7 @@ class MyApp(App):
|
|
|
59
62
|
yield Static("Welcome to claude SDK tutor!", id="header")
|
|
60
63
|
yield RichLog(markup=True, highlight=True)
|
|
61
64
|
yield LoadingIndicator(id="spinner")
|
|
62
|
-
yield
|
|
65
|
+
yield HistoryInput(history=self.history)
|
|
63
66
|
yield Footer()
|
|
64
67
|
|
|
65
68
|
async def on_mount(self) -> None:
|
|
@@ -85,8 +88,10 @@ class MyApp(App):
|
|
|
85
88
|
log.write(Panel(RichMarkdown(message), title="Slash", border_style="green"))
|
|
86
89
|
|
|
87
90
|
def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
88
|
-
self.query_one(Input).value = ""
|
|
89
91
|
command = event.value.strip()
|
|
92
|
+
self.query_one(HistoryInput).value = ""
|
|
93
|
+
if command:
|
|
94
|
+
self.history.add(command)
|
|
90
95
|
if command == "/clear":
|
|
91
96
|
self.run_worker(self.clear_conversation())
|
|
92
97
|
return
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-sdk-tutor"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.5"
|
|
4
4
|
description = "Add your description here"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"claude-agent-sdk>=0.1.26",
|
|
9
|
+
"platformdirs>=4.0.0",
|
|
9
10
|
"textual>=7.5.0",
|
|
10
11
|
"textual-dev>=1.8.0",
|
|
11
12
|
"watchfiles>=1.1.1",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from platformdirs import user_data_dir
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CommandHistory:
|
|
7
|
+
"""Manages command history with persistence to disk."""
|
|
8
|
+
|
|
9
|
+
MAX_ENTRIES = 1000
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.history: list[str] = []
|
|
13
|
+
self.index: int = -1
|
|
14
|
+
self.temp_input: str = ""
|
|
15
|
+
self._history_file = Path(user_data_dir("claude-sdk-tutor")) / "command_history.txt"
|
|
16
|
+
self._load()
|
|
17
|
+
|
|
18
|
+
def _load(self) -> None:
|
|
19
|
+
"""Load history from disk."""
|
|
20
|
+
if self._history_file.exists():
|
|
21
|
+
try:
|
|
22
|
+
lines = self._history_file.read_text().splitlines()
|
|
23
|
+
self.history = lines[-self.MAX_ENTRIES :]
|
|
24
|
+
except OSError:
|
|
25
|
+
self.history = []
|
|
26
|
+
|
|
27
|
+
def _save(self) -> None:
|
|
28
|
+
"""Save history to disk."""
|
|
29
|
+
try:
|
|
30
|
+
self._history_file.parent.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
self._history_file.write_text("\n".join(self.history[-self.MAX_ENTRIES :]))
|
|
32
|
+
except OSError:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def add(self, command: str) -> None:
|
|
36
|
+
"""Add a command to history, skipping consecutive duplicates."""
|
|
37
|
+
command = command.strip()
|
|
38
|
+
if not command:
|
|
39
|
+
return
|
|
40
|
+
if not self.history or self.history[-1] != command:
|
|
41
|
+
self.history.append(command)
|
|
42
|
+
self._save()
|
|
43
|
+
self.reset_navigation()
|
|
44
|
+
|
|
45
|
+
def reset_navigation(self) -> None:
|
|
46
|
+
"""Reset navigation state."""
|
|
47
|
+
self.index = -1
|
|
48
|
+
self.temp_input = ""
|
|
49
|
+
|
|
50
|
+
def navigate_up(self, current_input: str) -> str:
|
|
51
|
+
"""Navigate to previous command in history."""
|
|
52
|
+
if not self.history:
|
|
53
|
+
return current_input
|
|
54
|
+
|
|
55
|
+
if self.index == -1:
|
|
56
|
+
self.temp_input = current_input
|
|
57
|
+
self.index = len(self.history) - 1
|
|
58
|
+
elif self.index > 0:
|
|
59
|
+
self.index -= 1
|
|
60
|
+
|
|
61
|
+
return self.history[self.index]
|
|
62
|
+
|
|
63
|
+
def navigate_down(self, current_input: str) -> str:
|
|
64
|
+
"""Navigate to next command in history, or restore original input."""
|
|
65
|
+
if self.index == -1:
|
|
66
|
+
return current_input
|
|
67
|
+
|
|
68
|
+
if self.index < len(self.history) - 1:
|
|
69
|
+
self.index += 1
|
|
70
|
+
return self.history[self.index]
|
|
71
|
+
else:
|
|
72
|
+
self.index = -1
|
|
73
|
+
return self.temp_input
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from textual.binding import Binding
|
|
2
|
+
from textual.widgets import Input
|
|
3
|
+
|
|
4
|
+
from claude.history import CommandHistory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HistoryInput(Input):
|
|
8
|
+
"""Input widget with command history navigation."""
|
|
9
|
+
|
|
10
|
+
BINDINGS = [
|
|
11
|
+
Binding("up", "history_previous", "Previous command", show=False),
|
|
12
|
+
Binding("down", "history_next", "Next command", show=False),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
def __init__(self, history: CommandHistory, **kwargs):
|
|
16
|
+
super().__init__(**kwargs)
|
|
17
|
+
self.history = history
|
|
18
|
+
|
|
19
|
+
def action_history_previous(self) -> None:
|
|
20
|
+
"""Navigate to previous command in history."""
|
|
21
|
+
self.value = self.history.navigate_up(self.value)
|
|
22
|
+
self.cursor_position = len(self.value)
|
|
23
|
+
|
|
24
|
+
def action_history_next(self) -> None:
|
|
25
|
+
"""Navigate to next command in history."""
|
|
26
|
+
self.value = self.history.navigate_down(self.value)
|
|
27
|
+
self.cursor_position = len(self.value)
|
|
@@ -206,10 +206,11 @@ wheels = [
|
|
|
206
206
|
|
|
207
207
|
[[package]]
|
|
208
208
|
name = "claude-sdk-tutor"
|
|
209
|
-
version = "0.1.
|
|
209
|
+
version = "0.1.4"
|
|
210
210
|
source = { editable = "." }
|
|
211
211
|
dependencies = [
|
|
212
212
|
{ name = "claude-agent-sdk" },
|
|
213
|
+
{ name = "platformdirs" },
|
|
213
214
|
{ name = "textual" },
|
|
214
215
|
{ name = "textual-dev" },
|
|
215
216
|
{ name = "watchfiles" },
|
|
@@ -218,6 +219,7 @@ dependencies = [
|
|
|
218
219
|
[package.metadata]
|
|
219
220
|
requires-dist = [
|
|
220
221
|
{ name = "claude-agent-sdk", specifier = ">=0.1.26" },
|
|
222
|
+
{ name = "platformdirs", specifier = ">=4.0.0" },
|
|
221
223
|
{ name = "textual", specifier = ">=7.5.0" },
|
|
222
224
|
{ name = "textual-dev", specifier = ">=1.8.0" },
|
|
223
225
|
{ name = "watchfiles", specifier = ">=1.1.1" },
|
|
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
|