termuxcode 0.2.0__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.
termuxcode/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """TermuxCode - Python project for Termux development."""
2
+
3
+ __version__ = "0.2.0"
4
+
5
+ from .tui import ClaudeChat
6
+
7
+ __all__ = ['ClaudeChat']
termuxcode/cli.py ADDED
@@ -0,0 +1,12 @@
1
+ """CLI para ejecutar la TUI de termuxcode"""
2
+ from .tui.app import ClaudeChat
3
+
4
+
5
+ def main() -> None:
6
+ """Ejecutar la TUI de termuxcode"""
7
+ app = ClaudeChat()
8
+ app.run()
9
+
10
+
11
+ if __name__ == "__main__":
12
+ main()
@@ -0,0 +1,6 @@
1
+ """TUI para Claude Agent SDK - Chat Interface"""
2
+
3
+ from .app import ClaudeChat
4
+ from .history import MessageHistory
5
+
6
+ __all__ = ['ClaudeChat', 'MessageHistory']
@@ -0,0 +1,96 @@
1
+ """Módulo para comunicarse con el agente Claude con historial en JSONL"""
2
+ import os
3
+ from typing import TYPE_CHECKING
4
+
5
+ from claude_agent_sdk import query, ClaudeAgentOptions
6
+
7
+ from .history import MessageHistory
8
+
9
+ if TYPE_CHECKING:
10
+ from .chat import ChatLog
11
+
12
+
13
+ class AgentClient:
14
+ """Cliente para comunicarse con Claude Agent SDK con historial en JSONL"""
15
+
16
+ def __init__(
17
+ self,
18
+ chat_log: 'ChatLog',
19
+ history: MessageHistory,
20
+ cwd: str = None,
21
+ ):
22
+ self.chat_log = chat_log
23
+ self.history = history
24
+ self.cwd = cwd or os.getcwd()
25
+
26
+ async def query(self, prompt: str) -> None:
27
+ """Ejecutar query del agente con historial en JSONL"""
28
+
29
+ # Mostrar mensaje del usuario en la UI
30
+ self.chat_log.write_user(prompt)
31
+
32
+ # Cargar historial (ya está truncado a max_messages por save())
33
+ history = self.history.load()
34
+
35
+ # Construir prompt con el historial y el nuevo mensaje
36
+ full_prompt = self.history.build_prompt(history, prompt)
37
+
38
+ # Usar query() del SDK
39
+ options = ClaudeAgentOptions(
40
+ permission_mode="bypassPermissions",
41
+ cwd=self.cwd,
42
+ include_partial_messages=False,
43
+ cli_path="/data/data/com.termux/files/home/.claude/local/claude",
44
+ max_budget_usd=0.10,
45
+ )
46
+
47
+ old_claudecode = os.environ.pop('CLAUDECODE', None)
48
+ assistant_response = ""
49
+
50
+ try:
51
+ async for message in query(prompt=full_prompt, options=options):
52
+ await self._process_message(message)
53
+ # Acumular la respuesta del asistente
54
+ if hasattr(message, 'content') and isinstance(message.content, list):
55
+ for block in message.content:
56
+ if block.__class__.__name__ == "TextBlock":
57
+ assistant_response += block.text
58
+ finally:
59
+ if old_claudecode:
60
+ os.environ['CLAUDECODE'] = old_claudecode
61
+
62
+ # Guardar mensaje del usuario y respuesta del asistente en historial
63
+ self.history.append("user", prompt)
64
+ if assistant_response:
65
+ self.history.append("assistant", assistant_response)
66
+
67
+ async def _process_message(self, message) -> None:
68
+ """Procesar mensaje del agente"""
69
+ msg_type = message.__class__.__name__
70
+
71
+ if msg_type == "ResultMessage":
72
+ return
73
+ elif msg_type == "AssistantMessage":
74
+ await self._process_assistant(message)
75
+ elif msg_type == "UserMessage":
76
+ await self._process_user(message)
77
+
78
+ async def _process_assistant(self, message) -> None:
79
+ """Procesar AssistantMessage"""
80
+ if hasattr(message, 'content') and isinstance(message.content, list):
81
+ for block in message.content:
82
+ block_type = block.__class__.__name__
83
+
84
+ if block_type == "TextBlock":
85
+ self.chat_log.write_assistant(block.text)
86
+
87
+ elif block_type == "ToolUseBlock":
88
+ tool_input = str(block.input) if hasattr(block, 'input') else None
89
+ self.chat_log.write_tool(block.name, tool_input)
90
+
91
+ async def _process_user(self, message) -> None:
92
+ """Procesar UserMessage (tool results)"""
93
+ if hasattr(message, 'content') and isinstance(message.content, list):
94
+ for block in message.content:
95
+ if block.__class__.__name__ == "ToolResultBlock":
96
+ self.chat_log.write_result(str(block.content))
termuxcode/tui/app.py ADDED
@@ -0,0 +1,176 @@
1
+ """App principal - TUI responsive para Claude Agent SDK"""
2
+ from pathlib import Path
3
+ from textual.app import App, ComposeResult
4
+ from textual.containers import Vertical, VerticalScroll
5
+ from textual.widgets import Header, Input, Tabs, Tab
6
+
7
+ from .chat import ChatLog
8
+ from .agent import AgentClient
9
+ from .history import MessageHistory
10
+ from .sessions import SessionManager
11
+ from .styles import CSS
12
+
13
+
14
+ class ClaudeChat(App):
15
+ """TUI responsive para chat con Claude Agent SDK"""
16
+
17
+ CSS = CSS
18
+ TITLE = "Claude Chat"
19
+ AUTO_FOCUS = "#message-input"
20
+
21
+ BINDINGS = [
22
+ ("ctrl+n", "new_session", "Nueva sesión"),
23
+ ("ctrl+w", "close_session", "Cerrar sesión"),
24
+ ]
25
+
26
+ def __init__(self, cwd: str = None, max_history: int = 100):
27
+ super().__init__()
28
+ self.cwd = cwd or str(Path.cwd())
29
+ self.max_history = max_history
30
+ self.session_manager = SessionManager(Path(self.cwd) / ".sessions")
31
+ self._current_session_id: str | None = None
32
+ self._sessions: dict[str, MessageHistory] = {}
33
+ self.history: MessageHistory | None = None
34
+ self.agent: AgentClient | None = None
35
+
36
+ def compose(self) -> ComposeResult:
37
+ yield Header(id="header")
38
+ with VerticalScroll(id="chat-container"):
39
+ yield ChatLog(id="messages")
40
+ with Vertical(id="bottom-container"):
41
+ yield Tabs(id="sessions-tabs")
42
+ with Vertical(id="input-container"):
43
+ yield Input(id="message-input", placeholder="Escribe tu mensaje...")
44
+
45
+ def on_mount(self) -> None:
46
+ self.chat_log = self.query_one("#messages", ChatLog)
47
+ self.tabs = self.query_one("#sessions-tabs", Tabs)
48
+ self.input = self.query_one("#message-input", Input)
49
+ self.query_one("#chat-container").anchor() # Auto-scroll al final
50
+ self.call_later(self._load_first_session) # Cargar sesión inicial
51
+
52
+ async def _load_first_session(self) -> None:
53
+ """Cargar sesiones existentes o crear la primera al iniciar la app"""
54
+ sessions = self.session_manager.list_sessions()
55
+ if not sessions:
56
+ session = self.session_manager.create_session("Nueva sesión")
57
+ else:
58
+ last_id = self.session_manager.get_last_active()
59
+ session = self.session_manager.get_session(last_id) or sessions[0]
60
+
61
+ await self._switch_to_session(session.id)
62
+
63
+ async def _load_history(self) -> None:
64
+ """Cargar y mostrar el historial de mensajes"""
65
+ history = self.history.load()
66
+ for msg in history:
67
+ role = msg.get("role", "")
68
+ content = msg.get("content", "")
69
+ if role == "user":
70
+ self.chat_log.write_user(content)
71
+ elif role == "assistant":
72
+ self.chat_log.write_assistant(content)
73
+
74
+ async def _switch_to_session(self, session_id: str) -> None:
75
+ """Cambiar a una sesión específica"""
76
+ session = self.session_manager.get_session(session_id)
77
+ if not session:
78
+ return
79
+
80
+ self._current_session_id = session_id
81
+
82
+ # Obtener o crear MessageHistory para esta sesión
83
+ if session_id not in self._sessions:
84
+ self._sessions[session_id] = MessageHistory(
85
+ filename="messages.jsonl",
86
+ max_messages=self.max_history,
87
+ session_id=session_id,
88
+ cwd=self.cwd
89
+ )
90
+
91
+ self.history = self._sessions[session_id]
92
+ self.agent = AgentClient(self.chat_log, self.history, self.cwd)
93
+
94
+ # Actualizar tabs
95
+ self._update_tabs()
96
+
97
+ # Guardar última sesión activa
98
+ self.session_manager.set_last_active(session_id)
99
+
100
+ # Recargar historial en ChatLog
101
+ self.chat_log.clear()
102
+ await self._load_history()
103
+
104
+ def _update_tabs(self) -> None:
105
+ """Actualizar los tabs basado en sesiones existentes"""
106
+ self.tabs.clear()
107
+
108
+ for session in self.session_manager.list_sessions():
109
+ tab_id = f"tab-{session.id}"
110
+ self.tabs.add(Tab(session.name, id=tab_id))
111
+
112
+ # Activar tab actual
113
+ if self._current_session_id:
114
+ for tab in self.tabs.children:
115
+ if tab.id == f"tab-{self._current_session_id}":
116
+ self.tabs.active_tab = tab
117
+ break
118
+
119
+ def on_tabs_tab_activated(self, event: Tabs.TabActivated) -> None:
120
+ """Cambio de sesión al hacer clic o presionar Enter en un tab"""
121
+ tab_id = event.tab.id
122
+ if tab_id and tab_id.startswith("tab-"):
123
+ session_id = tab_id[4:] # Remover prefijo "tab-"
124
+ self.call_later(self._run_switch_session, session_id)
125
+
126
+ def _run_switch_session(self, session_id: str) -> None:
127
+ """Wrapper async para cambiar de sesión"""
128
+ import asyncio
129
+ asyncio.create_task(self._switch_to_session(session_id))
130
+
131
+ def action_new_session(self) -> None:
132
+ """Crear nueva sesión (Ctrl+N)"""
133
+ session = self.session_manager.create_session()
134
+ self.call_later(self._run_switch_session, session.id)
135
+ self.input.focus()
136
+
137
+ def action_close_session(self) -> None:
138
+ """Cerrar sesión actual (Ctrl+W)"""
139
+ sessions = self.session_manager.list_sessions()
140
+ if len(sessions) <= 1:
141
+ return # No cerrar la última sesión
142
+
143
+ if self._current_session_id:
144
+ self.session_manager.delete_session(self._current_session_id)
145
+ del self._sessions[self._current_session_id]
146
+
147
+ # Cambiar a la primera sesión disponible
148
+ sessions = self.session_manager.list_sessions()
149
+ self.call_later(self._run_switch_session, sessions[0].id)
150
+
151
+ def on_input_submitted(self, event: Input.Submitted) -> None:
152
+ if not event.value.strip():
153
+ return
154
+ prompt = event.value
155
+ event.input.clear()
156
+ self.call_later(self._run_query, prompt)
157
+
158
+ async def _run_query(self, prompt: str) -> None:
159
+ """Ejecutar query del agente"""
160
+ if self.agent is None:
161
+ self.chat_log.write_error("No session loaded. Please wait...")
162
+ return
163
+ await self.agent.query(prompt)
164
+
165
+
166
+ if __name__ == "__main__":
167
+ from pathlib import Path
168
+ import sys
169
+
170
+ project_root = Path(__file__).parent.parent.parent
171
+ src_path = project_root / "src"
172
+ if str(src_path) not in sys.path:
173
+ sys.path.insert(0, str(src_path))
174
+
175
+ app = ClaudeChat()
176
+ app.run()
termuxcode/tui/chat.py ADDED
@@ -0,0 +1,54 @@
1
+ """Widget de chat con auto-scroll, wrapping y markdown"""
2
+ from textual.widgets import RichLog
3
+ from rich.markdown import Markdown
4
+
5
+
6
+ class ChatLog(RichLog):
7
+ """Widget de chat con auto-scroll, word wrapping y markdown"""
8
+
9
+ def __init__(self, **kwargs):
10
+ super().__init__(
11
+ wrap=True,
12
+ auto_scroll=True,
13
+ markup=True,
14
+ min_width=0,
15
+ **kwargs
16
+ )
17
+
18
+ def write_user(self, content: str) -> None:
19
+ """Escribir mensaje del usuario"""
20
+ self.write(f"[bold cyan]You:[/] {content}\n")
21
+
22
+ def write_assistant(self, content: str) -> None:
23
+ """Escribir mensaje del asistente con soporte markdown"""
24
+ self.write(f"[bold green]Claude:[/]\n")
25
+ try:
26
+ md = Markdown(content)
27
+ self.write(md)
28
+ except Exception:
29
+ self.write(f"{content}\n")
30
+
31
+ def write_tool(self, tool_name: str, tool_input: str = None) -> None:
32
+ """Escribir herramienta usada (max 2 líneas)"""
33
+ self.write(f"[dim][yellow]🔧 {tool_name}[/yellow][/dim]")
34
+ if tool_input:
35
+ lines = str(tool_input).split('\n')[:2]
36
+ preview = '\n'.join(lines)
37
+ if len(lines) == 2 or len(tool_input) > len(preview):
38
+ preview = preview + "..."
39
+ self.write(f"[dim][sub]{preview}[/sub][/dim]")
40
+ self.write("")
41
+
42
+ def write_result(self, content: str) -> None:
43
+ """Escribir resultado de herramienta (max 2 líneas)"""
44
+ self.write(f"[dim][sub]✅ Result:[/sub][/dim]")
45
+ lines = str(content).split('\n')[:2]
46
+ preview = '\n'.join(lines)
47
+ if len(lines) == 2 or len(content) > len(preview):
48
+ preview = preview + "..."
49
+ self.write(f"[dim][sub]{preview}[/sub][/dim]")
50
+ self.write("")
51
+
52
+ def write_error(self, error: str) -> None:
53
+ """Escribir error"""
54
+ self.write(f"[bold red]❌ Error: {error}[/]\n")
@@ -0,0 +1,72 @@
1
+ """Módulo para manejo de historial de conversación en JSONL"""
2
+ import json
3
+ import uuid
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+
8
+ class MessageHistory:
9
+ """Gestiona el historial de mensajes en formato JSONL"""
10
+
11
+ def __init__(self, filename: str = "messages.jsonl", max_messages: int = 100,
12
+ session_id: str = None, cwd: str = None):
13
+ self.max_messages = max_messages
14
+ self.cwd = Path(cwd) if cwd else Path.cwd()
15
+ self.base_dir = self._get_history_dir()
16
+ self.session_id = session_id or str(uuid.uuid4())[:8]
17
+ self.filename = filename.replace(".jsonl", f"_{self.session_id}.jsonl")
18
+ self._history_file = self.base_dir / self.filename
19
+
20
+ def _get_history_dir(self) -> Path:
21
+ """Retorna el directorio donde se guarda el historial"""
22
+ sessions_dir = self.cwd / ".sessions"
23
+ sessions_dir.mkdir(parents=True, exist_ok=True)
24
+ return sessions_dir
25
+
26
+ def load(self) -> list[dict]:
27
+ """Carga el historial desde el archivo JSONL"""
28
+ if not self._history_file.exists():
29
+ return []
30
+ with open(self._history_file, 'r', encoding='utf-8') as f:
31
+ return [json.loads(line) for line in f if line.strip()]
32
+
33
+ def save(self, messages: list[dict]) -> None:
34
+ """Guarda el historial en el archivo JSONL (limitado a max_messages)"""
35
+ messages_to_save = messages[-self.max_messages:]
36
+ with open(self._history_file, 'w', encoding='utf-8') as f:
37
+ for msg in messages_to_save:
38
+ f.write(json.dumps(msg, ensure_ascii=False) + '\n')
39
+
40
+ def append(self, role: str, content: str) -> list[dict]:
41
+ """Agrega un mensaje al historial y lo guarda"""
42
+ history = self.load()
43
+ history.append({"role": role, "content": content})
44
+ self.save(history)
45
+ return history
46
+
47
+ def build_prompt(self, history: list[dict], new_message: str) -> str:
48
+ """Construye el prompt con el historial de conversación"""
49
+ prompt = ""
50
+ for msg in history:
51
+ role = msg.get("role", "")
52
+ content = msg.get("content", "")
53
+ if role == "user":
54
+ prompt += f"User: {content}\n\n"
55
+ elif role == "assistant":
56
+ prompt += f"Assistant: {content}\n\n"
57
+ prompt += f"User: {new_message}\n\nAssistant:"
58
+ return prompt
59
+
60
+ def clear(self) -> None:
61
+ """Limpia el historial"""
62
+ if self._history_file.exists():
63
+ self._history_file.unlink()
64
+
65
+ def count(self) -> int:
66
+ """Retorna la cantidad de mensajes en el historial"""
67
+ return len(self.load())
68
+
69
+ @property
70
+ def filepath(self) -> Path:
71
+ """Retorna la ruta del archivo de historial"""
72
+ return self._history_file
@@ -0,0 +1,113 @@
1
+ """Módulo para gestionar múltiples sesiones de chat"""
2
+ from dataclasses import dataclass, field
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+ import json
6
+ import uuid
7
+
8
+
9
+ @dataclass
10
+ class Session:
11
+ """Representa una sesión de chat"""
12
+ id: str
13
+ name: str
14
+ created_at: str
15
+ history_file: Path
16
+
17
+ @classmethod
18
+ def from_dict(cls, data: dict, sessions_dir: Path) -> "Session":
19
+ """Crear Session desde dict JSON"""
20
+ return cls(
21
+ id=data["id"],
22
+ name=data["name"],
23
+ created_at=data["created_at"],
24
+ history_file=sessions_dir / f"messages_{data['id']}.jsonl"
25
+ )
26
+
27
+ def to_dict(self) -> dict:
28
+ """Convertir a dict para JSON"""
29
+ return {
30
+ "id": self.id,
31
+ "name": self.name,
32
+ "created_at": self.created_at
33
+ }
34
+
35
+
36
+ class SessionManager:
37
+ """Gestiona múltiples sesiones de chat"""
38
+
39
+ def __init__(self, sessions_dir: Path):
40
+ self.sessions_dir = sessions_dir
41
+ self.sessions_dir.mkdir(parents=True, exist_ok=True)
42
+ self._index_file = sessions_dir / "sessions.json"
43
+ self._sessions: dict[str, Session] = {}
44
+ self._load_sessions()
45
+
46
+ def _load_sessions(self):
47
+ """Cargar sesiones desde el archivo de índice"""
48
+ if self._index_file.exists():
49
+ data = json.loads(self._index_file.read_text())
50
+ for s in data:
51
+ session = Session.from_dict(s, self.sessions_dir)
52
+ self._sessions[session.id] = session
53
+
54
+ def _save_sessions(self):
55
+ """Guardar sesiones al archivo de índice"""
56
+ data = [s.to_dict() for s in self._sessions.values()]
57
+ self._index_file.write_text(json.dumps(data, indent=2))
58
+
59
+ def create_session(self, name: str = None) -> Session:
60
+ """Crear una nueva sesión"""
61
+ session_id = str(uuid.uuid4())[:8]
62
+ name = name or f"Session {len(self._sessions) + 1}"
63
+ session = Session(
64
+ id=session_id,
65
+ name=name,
66
+ created_at=datetime.now().isoformat(),
67
+ history_file=self.sessions_dir / f"messages_{session_id}.jsonl"
68
+ )
69
+ self._sessions[session_id] = session
70
+ self._save_sessions()
71
+ return session
72
+
73
+ def list_sessions(self) -> list[Session]:
74
+ """Listar todas las sesiones, ordenadas por fecha descendente"""
75
+ return sorted(
76
+ self._sessions.values(),
77
+ key=lambda s: s.created_at,
78
+ reverse=True
79
+ )
80
+
81
+ def get_session(self, session_id: str) -> Session | None:
82
+ """Obtener una sesión por ID"""
83
+ return self._sessions.get(session_id)
84
+
85
+ def rename_session(self, session_id: str, new_name: str) -> bool:
86
+ """Renombrar una sesión"""
87
+ if session_id in self._sessions:
88
+ self._sessions[session_id].name = new_name
89
+ self._save_sessions()
90
+ return True
91
+ return False
92
+
93
+ def delete_session(self, session_id: str) -> bool:
94
+ """Eliminar una sesión y su archivo de historial"""
95
+ if session_id in self._sessions:
96
+ session = self._sessions[session_id]
97
+ if session.history_file.exists():
98
+ session.history_file.unlink()
99
+ del self._sessions[session_id]
100
+ self._save_sessions()
101
+ return True
102
+ return False
103
+
104
+ def get_last_active(self) -> str | None:
105
+ """Obtener el ID de la última sesión activa"""
106
+ last_file = self.sessions_dir / ".last_active"
107
+ if last_file.exists():
108
+ return last_file.read_text().strip()
109
+ return None
110
+
111
+ def set_last_active(self, session_id: str) -> None:
112
+ """Establecer la última sesión activa"""
113
+ (self.sessions_dir / ".last_active").write_text(session_id)
@@ -0,0 +1,71 @@
1
+ """CSS simple para layout vertical como mother.py"""
2
+
3
+ CSS = """
4
+ Screen {
5
+ layout: vertical;
6
+ }
7
+
8
+ /* Header - altura fija pequeña */
9
+ Header {
10
+ height: 3;
11
+ }
12
+
13
+ /* Contenedor del chat - ocupa el espacio restante */
14
+ VerticalScroll#chat-container {
15
+ height: 1fr;
16
+ width: 100%;
17
+ }
18
+
19
+ /* ChatLog */
20
+ ChatLog {
21
+ height: 100%;
22
+ width: 100%;
23
+ background: $surface;
24
+ color: $foreground;
25
+ scrollbar-gutter: auto;
26
+ }
27
+
28
+ /* Bottom container (tabs + input) - altura fija */
29
+ #bottom-container {
30
+ height: 5;
31
+ width: 100%;
32
+ background: $panel;
33
+ border-top: solid $primary;
34
+ }
35
+
36
+ /* Tabs */
37
+ Tabs {
38
+ height: 1;
39
+ background: $panel;
40
+ border-bottom: solid $primary 50%;
41
+ }
42
+
43
+ Tab {
44
+ padding: 0 2;
45
+ text-style: bold;
46
+ }
47
+
48
+ Tab.--active {
49
+ background: $primary;
50
+ color: $background;
51
+ }
52
+
53
+ /* Input container */
54
+ #input-container {
55
+ height: 3;
56
+ padding: 1 2;
57
+ }
58
+
59
+ /* Input */
60
+ #message-input {
61
+ width: 100%;
62
+ max-height: 3;
63
+ }
64
+
65
+ /* Placeholder del input */
66
+ #message-input > .input--placeholder {
67
+ color: $text 50%;
68
+ text-style: dim;
69
+ }
70
+
71
+ """
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: termuxcode
3
+ Version: 0.2.0
4
+ Summary: Python project for Termux development
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: claude-agent-sdk==0.1.48
8
+ Requires-Dist: textual==8.0.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
11
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
12
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
13
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
14
+ Requires-Dist: textual-dev==1.8.0; extra == "dev"
15
+
16
+ # TermuxCode
17
+
18
+ Python project for Termux development.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install -e .
24
+ ```
25
+
26
+ ## Development
27
+
28
+ ```bash
29
+ # Install development dependencies
30
+ pip install -e ".[dev]"
31
+
32
+ # Run tests
33
+ pytest
34
+
35
+ # Format code
36
+ ruff format .
37
+
38
+ # Lint code
39
+ ruff check .
40
+ ```
@@ -0,0 +1,14 @@
1
+ termuxcode/__init__.py,sha256=2M6qy6RWmUTwXUi0WJ3kb9tzBBR9FChm9nwlXxQ0nrA,136
2
+ termuxcode/cli.py,sha256=eXwO6IXd4OA8joYuy8iWVzRlJQWad_59xZDyk_1IEb0,216
3
+ termuxcode/tui/__init__.py,sha256=En-qENaywC5ONSk8gohasQNAcOuBWPi5yjPzOyBzcCk,158
4
+ termuxcode/tui/agent.py,sha256=4ZUnoml13Cg8O_RXd6opIpUzNPuLtCiv0Ij_iwh21mE,3552
5
+ termuxcode/tui/app.py,sha256=tNKgWCVddqN_BecrAh9m5Rrae0segNwnjiamZSwlwY0,6452
6
+ termuxcode/tui/chat.py,sha256=67l2ZOGoBdbpZ65OkoaMLLKiwH_sdUGnklPi777Ldwo,1936
7
+ termuxcode/tui/history.py,sha256=Bzp_8LrzzpRetcwNn1ghHCjmaR9XmEF4oM8iljPGqqY,2788
8
+ termuxcode/tui/sessions.py,sha256=2c1pHAWKGu9N7lRpWJ6grppylXplhDp3E794eKrBdK4,3800
9
+ termuxcode/tui/styles.py,sha256=eOSK54P24G4OQGPueGiYiJPWT3__PVsY78HZAxyMVPU,1065
10
+ termuxcode-0.2.0.dist-info/METADATA,sha256=OAZwArtZ0AVsaxx07VgeEz22z85VDMJiDAOrIt3TOz4,749
11
+ termuxcode-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
12
+ termuxcode-0.2.0.dist-info/entry_points.txt,sha256=UAjoJs1G65ITt11VEKCViHIjxgegpciyHtuc2itUZKI,51
13
+ termuxcode-0.2.0.dist-info/top_level.txt,sha256=__FTqr2MPCx4Yqtn4CceZjid4qLVn7UEQidi8oEHh-E,11
14
+ termuxcode-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ termuxcode = termuxcode.cli:main
@@ -0,0 +1 @@
1
+ termuxcode