tunacode-cli 0.0.22__py3-none-any.whl → 0.0.24__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.
Potentially problematic release.
This version of tunacode-cli might be problematic. Click here for more details.
- tunacode/cli/commands.py +1 -1
- tunacode/cli/main.py +5 -0
- tunacode/cli/repl.py +23 -8
- tunacode/cli/textual_app.py +19 -25
- tunacode/cli/textual_bridge.py +2 -3
- tunacode/constants.py +1 -1
- tunacode/context.py +0 -2
- tunacode/core/agents/main.py +21 -18
- tunacode/core/llm/planner.py +0 -1
- tunacode/core/setup/config_setup.py +6 -2
- tunacode/prompts/system.md +92 -0
- tunacode/tools/__init__.py +1 -1
- tunacode/tools/grep.py +2 -2
- tunacode/types.py +4 -0
- tunacode/ui/completers.py +5 -4
- tunacode/ui/input.py +1 -2
- tunacode/ui/lexers.py +0 -1
- tunacode/ui/output.py +2 -2
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/METADATA +20 -1
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/RECORD +24 -23
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/WHEEL +0 -0
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/entry_points.txt +0 -0
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/licenses/LICENSE +0 -0
- {tunacode_cli-0.0.22.dist-info → tunacode_cli-0.0.24.dist-info}/top_level.txt +0 -0
tunacode/cli/commands.py
CHANGED
|
@@ -192,7 +192,7 @@ class ArchitectCommand(SimpleCommand):
|
|
|
192
192
|
await ui.error("Usage: /architect [on|off]")
|
|
193
193
|
return
|
|
194
194
|
else:
|
|
195
|
-
state.architect_mode = not getattr(state,
|
|
195
|
+
state.architect_mode = not getattr(state, "architect_mode", False)
|
|
196
196
|
status = "ON" if state.architect_mode else "OFF"
|
|
197
197
|
if state.architect_mode:
|
|
198
198
|
await ui.success(f"Architect mode {status} - Requests will be planned before execution")
|
tunacode/cli/main.py
CHANGED
|
@@ -14,6 +14,7 @@ from tunacode.core.state import StateManager
|
|
|
14
14
|
from tunacode.setup import setup
|
|
15
15
|
from tunacode.ui import console as ui
|
|
16
16
|
from tunacode.utils.system import check_for_updates
|
|
17
|
+
from tunacode.exceptions import UserAbortError
|
|
17
18
|
|
|
18
19
|
app_settings = ApplicationSettings()
|
|
19
20
|
app = typer.Typer(help="🐟 TunaCode - Your AI-powered development assistant")
|
|
@@ -49,8 +50,12 @@ def main(
|
|
|
49
50
|
try:
|
|
50
51
|
await setup(run_setup, state_manager, cli_config)
|
|
51
52
|
await repl(state_manager)
|
|
53
|
+
except (KeyboardInterrupt, UserAbortError):
|
|
54
|
+
update_task.cancel()
|
|
55
|
+
return
|
|
52
56
|
except Exception as e:
|
|
53
57
|
from tunacode.exceptions import ConfigurationError
|
|
58
|
+
|
|
54
59
|
if isinstance(e, ConfigurationError):
|
|
55
60
|
# ConfigurationError already printed helpful message, just exit cleanly
|
|
56
61
|
update_task.cancel() # Cancel the update check
|
tunacode/cli/repl.py
CHANGED
|
@@ -172,7 +172,7 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
172
172
|
return _tool_handler(part, node, state_manager)
|
|
173
173
|
|
|
174
174
|
# Check if architect mode is enabled
|
|
175
|
-
if getattr(state_manager.session,
|
|
175
|
+
if getattr(state_manager.session, "architect_mode", False):
|
|
176
176
|
# Expand @file references before sending to the orchestrator
|
|
177
177
|
try:
|
|
178
178
|
from tunacode.utils.text_utils import expand_file_refs
|
|
@@ -184,14 +184,18 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
184
184
|
# Use orchestrator for planning and execution
|
|
185
185
|
orchestrator = OrchestratorAgent(state_manager)
|
|
186
186
|
results = await orchestrator.run(text, state_manager.session.current_model)
|
|
187
|
-
|
|
187
|
+
|
|
188
188
|
if output:
|
|
189
189
|
# Process results from all sub-agents
|
|
190
190
|
for res in results:
|
|
191
191
|
# Check if result exists and has output
|
|
192
|
-
if
|
|
192
|
+
if (
|
|
193
|
+
hasattr(res, "result")
|
|
194
|
+
and res.result is not None
|
|
195
|
+
and hasattr(res.result, "output")
|
|
196
|
+
):
|
|
193
197
|
await ui.agent(res.result.output)
|
|
194
|
-
|
|
198
|
+
|
|
195
199
|
if not results:
|
|
196
200
|
# Fallback: show that the request was processed
|
|
197
201
|
await ui.muted("Request completed")
|
|
@@ -204,7 +208,7 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
204
208
|
except ValueError as e:
|
|
205
209
|
await ui.error(str(e))
|
|
206
210
|
return
|
|
207
|
-
|
|
211
|
+
|
|
208
212
|
# Use normal agent processing
|
|
209
213
|
res = await agent.process_request(
|
|
210
214
|
state_manager.session.current_model,
|
|
@@ -219,7 +223,11 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
219
223
|
if isinstance(msg, dict) and "thought" in msg:
|
|
220
224
|
await ui.muted(f"THOUGHT: {msg['thought']}")
|
|
221
225
|
# Check if result exists and has output
|
|
222
|
-
if
|
|
226
|
+
if (
|
|
227
|
+
hasattr(res, "result")
|
|
228
|
+
and res.result is not None
|
|
229
|
+
and hasattr(res.result, "output")
|
|
230
|
+
):
|
|
223
231
|
await ui.agent(res.result.output)
|
|
224
232
|
else:
|
|
225
233
|
# Fallback: show that the request was processed
|
|
@@ -274,6 +282,7 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
274
282
|
|
|
275
283
|
async def repl(state_manager: StateManager):
|
|
276
284
|
action = None
|
|
285
|
+
ctrl_c_pressed = False
|
|
277
286
|
|
|
278
287
|
# Professional startup information
|
|
279
288
|
await ui.muted(f"• Model: {state_manager.session.current_model}")
|
|
@@ -286,12 +295,18 @@ async def repl(state_manager: StateManager):
|
|
|
286
295
|
while True:
|
|
287
296
|
try:
|
|
288
297
|
line = await ui.multiline_input(state_manager, _command_registry)
|
|
289
|
-
except
|
|
290
|
-
|
|
298
|
+
except UserAbortError:
|
|
299
|
+
if ctrl_c_pressed:
|
|
300
|
+
break
|
|
301
|
+
ctrl_c_pressed = True
|
|
302
|
+
await ui.warning("Hit Ctrl+C again to exit")
|
|
303
|
+
continue
|
|
291
304
|
|
|
292
305
|
if not line:
|
|
293
306
|
continue
|
|
294
307
|
|
|
308
|
+
ctrl_c_pressed = False
|
|
309
|
+
|
|
295
310
|
if line.lower() in ["exit", "quit"]:
|
|
296
311
|
break
|
|
297
312
|
|
tunacode/cli/textual_app.py
CHANGED
|
@@ -11,18 +11,13 @@ Provides a rich, interactive terminal user interface with:
|
|
|
11
11
|
import asyncio
|
|
12
12
|
from typing import Optional
|
|
13
13
|
|
|
14
|
-
from
|
|
15
|
-
from textual import on, work
|
|
14
|
+
from textual import on
|
|
16
15
|
from textual.app import App, ComposeResult
|
|
17
16
|
from textual.binding import Binding
|
|
18
17
|
from textual.containers import Container, Horizontal, Vertical, VerticalScroll
|
|
19
18
|
from textual.message import Message
|
|
20
|
-
from textual.
|
|
21
|
-
from textual.widgets import Button, Footer, Header, Input, Label
|
|
22
|
-
from textual.widgets import Markdown as MarkdownWidget
|
|
23
|
-
from textual.widgets import Static, TabbedContent, TabPane, TextArea
|
|
19
|
+
from textual.widgets import Button, Footer, Header, Static, TextArea
|
|
24
20
|
|
|
25
|
-
from tunacode.configuration.settings import ApplicationSettings
|
|
26
21
|
from tunacode.core.state import StateManager
|
|
27
22
|
from tunacode.setup import setup
|
|
28
23
|
from tunacode.utils.system import check_for_updates
|
|
@@ -130,78 +125,78 @@ class TunaCodeApp(App):
|
|
|
130
125
|
border: thick $primary;
|
|
131
126
|
padding: 1;
|
|
132
127
|
}
|
|
133
|
-
|
|
128
|
+
|
|
134
129
|
.sidebar-title {
|
|
135
130
|
text-align: center;
|
|
136
131
|
color: $primary;
|
|
137
132
|
margin-bottom: 1;
|
|
138
133
|
}
|
|
139
|
-
|
|
134
|
+
|
|
140
135
|
.section-title {
|
|
141
136
|
color: $accent;
|
|
142
137
|
margin: 1 0;
|
|
143
138
|
}
|
|
144
|
-
|
|
139
|
+
|
|
145
140
|
.command-item {
|
|
146
141
|
color: $text-muted;
|
|
147
142
|
margin-left: 1;
|
|
148
143
|
}
|
|
149
|
-
|
|
144
|
+
|
|
150
145
|
.status-ready {
|
|
151
146
|
color: $success;
|
|
152
147
|
}
|
|
153
|
-
|
|
148
|
+
|
|
154
149
|
.status-busy {
|
|
155
150
|
color: $warning;
|
|
156
151
|
}
|
|
157
|
-
|
|
152
|
+
|
|
158
153
|
.status-error {
|
|
159
154
|
color: $error;
|
|
160
155
|
}
|
|
161
|
-
|
|
156
|
+
|
|
162
157
|
ChatHistory {
|
|
163
158
|
border: thick $primary;
|
|
164
159
|
padding: 1;
|
|
165
160
|
height: 1fr;
|
|
166
161
|
}
|
|
167
|
-
|
|
162
|
+
|
|
168
163
|
.user-message {
|
|
169
164
|
background: $surface;
|
|
170
165
|
border-left: thick $primary;
|
|
171
166
|
padding: 1;
|
|
172
167
|
margin: 1 0;
|
|
173
168
|
}
|
|
174
|
-
|
|
169
|
+
|
|
175
170
|
.agent-message {
|
|
176
171
|
background: $surface;
|
|
177
172
|
border-left: thick $success;
|
|
178
173
|
padding: 1;
|
|
179
174
|
margin: 1 0;
|
|
180
175
|
}
|
|
181
|
-
|
|
176
|
+
|
|
182
177
|
.system-message {
|
|
183
178
|
background: $surface;
|
|
184
179
|
border-left: thick $warning;
|
|
185
180
|
padding: 1;
|
|
186
181
|
margin: 1 0;
|
|
187
182
|
}
|
|
188
|
-
|
|
183
|
+
|
|
189
184
|
.tool-message {
|
|
190
185
|
background: $surface;
|
|
191
186
|
border-left: thick $accent;
|
|
192
187
|
padding: 1;
|
|
193
188
|
margin: 1 0;
|
|
194
189
|
}
|
|
195
|
-
|
|
190
|
+
|
|
196
191
|
InputArea {
|
|
197
192
|
height: 5;
|
|
198
193
|
padding: 1;
|
|
199
194
|
}
|
|
200
|
-
|
|
195
|
+
|
|
201
196
|
#message-input {
|
|
202
197
|
height: 3;
|
|
203
198
|
}
|
|
204
|
-
|
|
199
|
+
|
|
205
200
|
#send-button {
|
|
206
201
|
width: 10;
|
|
207
202
|
margin-left: 1;
|
|
@@ -250,7 +245,8 @@ class TunaCodeApp(App):
|
|
|
250
245
|
)
|
|
251
246
|
self.chat_history.add_message(
|
|
252
247
|
"System",
|
|
253
|
-
"⚠️ IMPORTANT: Always use git branches before making major changes\
|
|
248
|
+
"⚠️ IMPORTANT: Always use git branches before making major changes\n"
|
|
249
|
+
"Type '/help' for available commands",
|
|
254
250
|
"system",
|
|
255
251
|
)
|
|
256
252
|
|
|
@@ -280,7 +276,7 @@ class TunaCodeApp(App):
|
|
|
280
276
|
"""Handle slash commands."""
|
|
281
277
|
if command == "/help":
|
|
282
278
|
help_text = """Available Commands:
|
|
283
|
-
|
|
279
|
+
|
|
284
280
|
/help - Show this help message
|
|
285
281
|
/clear - Clear chat history
|
|
286
282
|
/model - Show current model info
|
|
@@ -371,8 +367,6 @@ def main():
|
|
|
371
367
|
|
|
372
368
|
# Initialize state manager
|
|
373
369
|
state_manager = StateManager()
|
|
374
|
-
app_settings = ApplicationSettings()
|
|
375
|
-
|
|
376
370
|
# Show banner
|
|
377
371
|
print("🐟 TunaCode - Modern AI Development Assistant")
|
|
378
372
|
print("=" * 50)
|
tunacode/cli/textual_bridge.py
CHANGED
|
@@ -5,9 +5,8 @@ This module adapts the existing REPL and agent processing logic to work
|
|
|
5
5
|
with the new Textual-based interface while maintaining compatibility.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import asyncio
|
|
9
8
|
from asyncio.exceptions import CancelledError
|
|
10
|
-
from typing import Callable
|
|
9
|
+
from typing import Callable
|
|
11
10
|
|
|
12
11
|
from pydantic_ai.exceptions import UnexpectedModelBehavior
|
|
13
12
|
|
|
@@ -129,7 +128,7 @@ class TextualAgentBridge:
|
|
|
129
128
|
# Check if confirmation is needed
|
|
130
129
|
if tool_handler.should_confirm(part.tool_name):
|
|
131
130
|
# Create confirmation request
|
|
132
|
-
|
|
131
|
+
tool_handler.create_confirmation_request(part.tool_name, args)
|
|
133
132
|
|
|
134
133
|
# For now, show a simple confirmation in the UI
|
|
135
134
|
# In a full implementation, this would show a proper modal dialog
|
tunacode/constants.py
CHANGED
tunacode/context.py
CHANGED
tunacode/core/agents/main.py
CHANGED
|
@@ -7,11 +7,22 @@ Handles agent creation, configuration, and request processing.
|
|
|
7
7
|
import json
|
|
8
8
|
import re
|
|
9
9
|
from datetime import datetime, timezone
|
|
10
|
+
from pathlib import Path
|
|
10
11
|
from typing import Optional
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
from tunacode.core.state import StateManager
|
|
14
|
+
from tunacode.services.mcp import get_mcp_servers
|
|
15
|
+
from tunacode.tools.bash import bash
|
|
16
|
+
from tunacode.tools.grep import grep
|
|
17
|
+
from tunacode.tools.read_file import read_file
|
|
18
|
+
from tunacode.tools.run_command import run_command
|
|
19
|
+
from tunacode.tools.update_file import update_file
|
|
20
|
+
from tunacode.tools.write_file import write_file
|
|
21
|
+
from tunacode.types import (AgentRun, ErrorMessage, ModelName, PydanticAgent, ToolCallback,
|
|
22
|
+
ToolCallId, ToolName)
|
|
13
23
|
|
|
14
24
|
|
|
25
|
+
# Lazy import for Agent and Tool
|
|
15
26
|
def get_agent_tool():
|
|
16
27
|
import importlib
|
|
17
28
|
|
|
@@ -26,18 +37,6 @@ def get_model_messages():
|
|
|
26
37
|
return messages.ModelRequest, messages.ToolReturnPart
|
|
27
38
|
|
|
28
39
|
|
|
29
|
-
from tunacode.core.state import StateManager
|
|
30
|
-
from tunacode.services.mcp import get_mcp_servers
|
|
31
|
-
from tunacode.tools.bash import bash
|
|
32
|
-
from tunacode.tools.grep import grep
|
|
33
|
-
from tunacode.tools.read_file import read_file
|
|
34
|
-
from tunacode.tools.run_command import run_command
|
|
35
|
-
from tunacode.tools.update_file import update_file
|
|
36
|
-
from tunacode.tools.write_file import write_file
|
|
37
|
-
from tunacode.types import (AgentRun, ErrorMessage, ModelName, PydanticAgent, ToolCallback,
|
|
38
|
-
ToolCallId, ToolName)
|
|
39
|
-
|
|
40
|
-
|
|
41
40
|
async def _process_node(node, tool_callback: Optional[ToolCallback], state_manager: StateManager):
|
|
42
41
|
if hasattr(node, "request"):
|
|
43
42
|
state_manager.session.messages.append(node.request)
|
|
@@ -125,21 +124,25 @@ async def _process_node(node, tool_callback: Optional[ToolCallback], state_manag
|
|
|
125
124
|
|
|
126
125
|
def get_or_create_agent(model: ModelName, state_manager: StateManager) -> PydanticAgent:
|
|
127
126
|
if model not in state_manager.session.agents:
|
|
128
|
-
max_retries = state_manager.session.user_config
|
|
127
|
+
max_retries = state_manager.session.user_config.get("settings", {}).get("max_retries", 3)
|
|
129
128
|
|
|
130
129
|
# Lazy import Agent and Tool
|
|
131
130
|
Agent, Tool = get_agent_tool()
|
|
132
131
|
|
|
133
132
|
# Load system prompt
|
|
134
|
-
import os
|
|
135
|
-
from pathlib import Path
|
|
136
|
-
|
|
137
133
|
prompt_path = Path(__file__).parent.parent.parent / "prompts" / "system.md"
|
|
138
134
|
try:
|
|
139
135
|
with open(prompt_path, "r", encoding="utf-8") as f:
|
|
140
136
|
system_prompt = f.read().strip()
|
|
141
137
|
except FileNotFoundError:
|
|
142
|
-
|
|
138
|
+
# Fallback to system.txt if system.md not found
|
|
139
|
+
prompt_path = Path(__file__).parent.parent.parent / "prompts" / "system.txt"
|
|
140
|
+
try:
|
|
141
|
+
with open(prompt_path, "r", encoding="utf-8") as f:
|
|
142
|
+
system_prompt = f.read().strip()
|
|
143
|
+
except FileNotFoundError:
|
|
144
|
+
# Use a default system prompt if neither file exists
|
|
145
|
+
system_prompt = "You are a helpful AI assistant for software development tasks."
|
|
143
146
|
|
|
144
147
|
state_manager.session.agents[model] = Agent(
|
|
145
148
|
model=model,
|
tunacode/core/llm/planner.py
CHANGED
|
@@ -99,11 +99,15 @@ class ConfigSetup(BaseSetup):
|
|
|
99
99
|
" [green]tunacode --model 'anthropic:claude-3-opus' --key 'your-key'[/green]"
|
|
100
100
|
)
|
|
101
101
|
console.print(
|
|
102
|
-
" [green]tunacode --model 'openrouter:anthropic/claude-3.5-sonnet'
|
|
102
|
+
" [green]tunacode --model 'openrouter:anthropic/claude-3.5-sonnet' "
|
|
103
|
+
"--key 'your-key' --baseurl 'https://openrouter.ai/api/v1'[/green]"
|
|
103
104
|
)
|
|
104
105
|
console.print("\n[yellow]Run 'tunacode --help' for more options[/yellow]\n")
|
|
105
106
|
from tunacode.exceptions import ConfigurationError
|
|
106
|
-
|
|
107
|
+
|
|
108
|
+
raise ConfigurationError(
|
|
109
|
+
"No configuration found. Please use CLI flags to configure."
|
|
110
|
+
)
|
|
107
111
|
|
|
108
112
|
if not self.state_manager.session.user_config.get("default_model"):
|
|
109
113
|
raise ConfigurationError(
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
\###Instruction###
|
|
2
|
+
|
|
3
|
+
You are **"TunaCode"**, a **senior software developer AI assistant operating inside the user's terminal (CLI)**.
|
|
4
|
+
|
|
5
|
+
**YOU ARE NOT A CHATBOT. YOU ARE AN OPERATIONAL AGENT WITH TOOLS.**
|
|
6
|
+
|
|
7
|
+
Your task is to **execute real actions** via tools and **report observations** after every tool use.
|
|
8
|
+
|
|
9
|
+
You MUST follow these rules:
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
\###Tool Access Rules###
|
|
14
|
+
|
|
15
|
+
You HAVE the following tools available. USE THEM IMMEDIATELY and CONSTANTLY:
|
|
16
|
+
|
|
17
|
+
* `run_command(command: str)` — Execute any shell command
|
|
18
|
+
* `read_file(filepath: str)` — Read any file
|
|
19
|
+
* `write_file(filepath: str, content: str)` — Create or write any file
|
|
20
|
+
* `update_file(filepath: str, target: str, patch: str)` — Update existing files
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
\###Mandatory Operating Principles###
|
|
25
|
+
|
|
26
|
+
1. **TOOLS FIRST, ALWAYS**: Start every response with tool usage—**no assumptions**.
|
|
27
|
+
2. **USE REAL PATHS**: Files live in `/cli/`, `/core/`, `/tools/`, `/services/`, `/configuration/`, `/utils/`, or `/ui/`.
|
|
28
|
+
3. **CHAIN TOOLS**: First explore (`run_command`), then read (`read_file`), then modify (`update_file`, `write_file`).
|
|
29
|
+
4. **ACT IMMEDIATELY**: Don’t describe what to do—**just do it**.
|
|
30
|
+
5. **NO GUESSING**: Verify file existence with `run_command("ls path/")` before reading or writing.
|
|
31
|
+
6. **ASSUME NOTHING**: Always fetch and verify before responding.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
\###Prompt Design Style###
|
|
36
|
+
|
|
37
|
+
* Be **blunt and direct**. Avoid soft language (e.g., “please,” “let me,” “I think”).
|
|
38
|
+
* **Use role-specific language**: you are a CLI-level senior engineer, not a tutor or assistant.
|
|
39
|
+
* Write using affirmative imperatives: *Do this. Check that. Show me.*
|
|
40
|
+
* Ask for clarification if needed: “Specify the path.” / “Which class do you mean?”
|
|
41
|
+
* Break complex requests into sequenced tool actions.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
\###Example Prompts (Correct vs Incorrect)###
|
|
46
|
+
|
|
47
|
+
**User**: What's in the tools directory?
|
|
48
|
+
✅ `run_command("ls -la tools/")`
|
|
49
|
+
❌ "The tools directory likely includes..."
|
|
50
|
+
|
|
51
|
+
**User**: Fix the import in `core/agents/main.py`
|
|
52
|
+
✅ `read_file("core/agents/main.py")`, then `update_file("core/agents/main.py", "from old_module", "from new_module")`
|
|
53
|
+
❌ "To fix the import, modify the code to..."
|
|
54
|
+
|
|
55
|
+
**User**: What commands are available?
|
|
56
|
+
✅ `run_command("grep -E 'class.*Command' cli/commands.py")`
|
|
57
|
+
❌ "Available commands usually include..."
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
\###Meta Behavior###
|
|
62
|
+
|
|
63
|
+
Use the **ReAct** (Reasoning + Action) framework:
|
|
64
|
+
|
|
65
|
+
* {"thought": "I need to inspect the file before modifying."}
|
|
66
|
+
* → run tool
|
|
67
|
+
* {"thought": "I see the old import. Now I'll patch it."}
|
|
68
|
+
* → update file
|
|
69
|
+
* {"thought": "Patch complete. Ready for next instruction."}
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
\###Reminder###
|
|
74
|
+
|
|
75
|
+
You were created by **tunahorse21**.
|
|
76
|
+
You are not a chatbot.
|
|
77
|
+
You are an autonomous code execution agent.
|
|
78
|
+
You will be penalized for failing to use tools.
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
\###Example###
|
|
82
|
+
|
|
83
|
+
```plaintext
|
|
84
|
+
User: What’s the current app version?
|
|
85
|
+
|
|
86
|
+
THINK: {"thought": "I should search for APP_VERSION in the constants file."}
|
|
87
|
+
ACT: run_command("grep -n 'APP_VERSION' constants.py")
|
|
88
|
+
OBSERVE: {"thought": "Found APP_VERSION at line 12."}
|
|
89
|
+
ACT: read_file("constants.py")
|
|
90
|
+
OBSERVE: {"thought": "APP_VERSION is set to '2.4.1'. This is the current version."}
|
|
91
|
+
RESPONSE: "Current version is 2.4.1 (from constants.py)"
|
|
92
|
+
```
|
tunacode/tools/__init__.py
CHANGED
tunacode/tools/grep.py
CHANGED
|
@@ -16,7 +16,7 @@ import subprocess
|
|
|
16
16
|
from concurrent.futures import ThreadPoolExecutor
|
|
17
17
|
from dataclasses import dataclass
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import
|
|
19
|
+
from typing import List, Optional
|
|
20
20
|
|
|
21
21
|
from tunacode.exceptions import ToolExecutionError
|
|
22
22
|
from tunacode.tools.base import BaseTool
|
|
@@ -239,7 +239,7 @@ class ParallelGrep(BaseTool):
|
|
|
239
239
|
results = await self._ripgrep_search(pattern, directory, config)
|
|
240
240
|
if results:
|
|
241
241
|
return results
|
|
242
|
-
except:
|
|
242
|
+
except Exception:
|
|
243
243
|
pass
|
|
244
244
|
|
|
245
245
|
# Fallback to Python implementation
|
tunacode/types.py
CHANGED
|
@@ -107,9 +107,13 @@ class UILogger(Protocol):
|
|
|
107
107
|
"""Protocol for UI logging operations."""
|
|
108
108
|
|
|
109
109
|
async def info(self, message: str) -> None: ...
|
|
110
|
+
|
|
110
111
|
async def error(self, message: str) -> None: ...
|
|
112
|
+
|
|
111
113
|
async def warning(self, message: str) -> None: ...
|
|
114
|
+
|
|
112
115
|
async def debug(self, message: str) -> None: ...
|
|
116
|
+
|
|
113
117
|
async def success(self, message: str) -> None: ...
|
|
114
118
|
|
|
115
119
|
|
tunacode/ui/completers.py
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"""Completers for file references and commands."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
from typing import Iterable, Optional
|
|
4
|
+
from typing import TYPE_CHECKING, Iterable, Optional
|
|
5
5
|
|
|
6
6
|
from prompt_toolkit.completion import CompleteEvent, Completer, Completion, merge_completers
|
|
7
7
|
from prompt_toolkit.document import Document
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..cli.commands import CommandRegistry
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class CommandCompleter(Completer):
|
|
13
14
|
"""Completer for slash commands."""
|
|
14
15
|
|
|
15
|
-
def __init__(self, command_registry: Optional[CommandRegistry] = None):
|
|
16
|
+
def __init__(self, command_registry: Optional["CommandRegistry"] = None):
|
|
16
17
|
self.command_registry = command_registry
|
|
17
18
|
|
|
18
19
|
def get_completions(
|
|
@@ -120,7 +121,7 @@ class FileReferenceCompleter(Completer):
|
|
|
120
121
|
pass
|
|
121
122
|
|
|
122
123
|
|
|
123
|
-
def create_completer(command_registry: Optional[CommandRegistry] = None) -> Completer:
|
|
124
|
+
def create_completer(command_registry: Optional["CommandRegistry"] = None) -> Completer:
|
|
124
125
|
"""Create a merged completer for both commands and file references."""
|
|
125
126
|
return merge_completers(
|
|
126
127
|
[
|
tunacode/ui/input.py
CHANGED
|
@@ -4,10 +4,9 @@ from typing import Optional
|
|
|
4
4
|
|
|
5
5
|
from prompt_toolkit.formatted_text import HTML
|
|
6
6
|
from prompt_toolkit.key_binding import KeyBindings
|
|
7
|
-
from prompt_toolkit.styles import Style
|
|
8
7
|
from prompt_toolkit.validation import Validator
|
|
9
8
|
|
|
10
|
-
from tunacode.constants import
|
|
9
|
+
from tunacode.constants import UI_PROMPT_PREFIX
|
|
11
10
|
from tunacode.core.state import StateManager
|
|
12
11
|
|
|
13
12
|
from .completers import create_completer
|
tunacode/ui/lexers.py
CHANGED
tunacode/ui/output.py
CHANGED
|
@@ -19,8 +19,8 @@ colors = DotDict(UI_COLORS)
|
|
|
19
19
|
BANNER = """[bold cyan]
|
|
20
20
|
████████╗██╗ ██╗███╗ ██╗ █████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
21
21
|
╚══██╔══╝██║ ██║████╗ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗██╔════╝
|
|
22
|
-
██║ ██║ ██║██╔██╗ ██║███████║██║ ██║ ██║██║ ██║█████╗
|
|
23
|
-
██║ ██║ ██║██║╚██╗██║██╔══██║██║ ██║ ██║██║ ██║██╔══╝
|
|
22
|
+
██║ ██║ ██║██╔██╗ ██║███████║██║ ██║ ██║██║ ██║█████╗
|
|
23
|
+
██║ ██║ ██║██║╚██╗██║██╔══██║██║ ██║ ██║██║ ██║██╔══╝
|
|
24
24
|
██║ ╚██████╔╝██║ ╚████║██║ ██║╚██████╗╚██████╔╝██████╔╝███████╗
|
|
25
25
|
╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
|
|
26
26
|
[/bold cyan]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunacode-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.24
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -30,6 +30,7 @@ Requires-Dist: black; extra == "dev"
|
|
|
30
30
|
Requires-Dist: flake8; extra == "dev"
|
|
31
31
|
Requires-Dist: isort; extra == "dev"
|
|
32
32
|
Requires-Dist: pytest; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
33
34
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
35
|
Requires-Dist: textual-dev; extra == "dev"
|
|
35
36
|
Dynamic: license-file
|
|
@@ -131,6 +132,24 @@ Dynamic: license-file
|
|
|
131
132
|
pip install tunacode-cli
|
|
132
133
|
```
|
|
133
134
|
|
|
135
|
+
#### Development Installation
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Clone the repository
|
|
139
|
+
git clone https://github.com/larock22/tunacode.git
|
|
140
|
+
cd tunacode
|
|
141
|
+
|
|
142
|
+
# Run the setup script
|
|
143
|
+
./scripts/setup_dev_env.sh
|
|
144
|
+
|
|
145
|
+
# Or manually:
|
|
146
|
+
python3 -m venv venv
|
|
147
|
+
source venv/bin/activate
|
|
148
|
+
pip install -e ".[dev]"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed development setup.
|
|
152
|
+
|
|
134
153
|
#### One-line Install (Linux/macOS)
|
|
135
154
|
|
|
136
155
|
```bash
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
tunacode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
tunacode/constants.py,sha256=
|
|
3
|
-
tunacode/context.py,sha256=
|
|
2
|
+
tunacode/constants.py,sha256=UXLTZopdI4tNlRFmB5uApx45cRqJ61gZVCLaOlw80TI,3799
|
|
3
|
+
tunacode/context.py,sha256=6sterdRvPOyG3LU0nEAXpBsEPZbO3qtPyTlJBi-_VXE,2612
|
|
4
4
|
tunacode/exceptions.py,sha256=_Dyj6cC0868dMABekdQHXCg5XhucJumbGUMXaSDzgB4,2645
|
|
5
5
|
tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
tunacode/setup.py,sha256=dYn0NeAxtNIDSogWEmGSyjb9wsr8AonZ8vAo5sw9NIw,1909
|
|
7
|
-
tunacode/types.py,sha256=
|
|
7
|
+
tunacode/types.py,sha256=wH0nqGTJ_yllLzbhTJpiYjy30LDAmSqfWgzuOUZ0ZHM,7150
|
|
8
8
|
tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
|
|
9
|
-
tunacode/cli/commands.py,sha256=
|
|
10
|
-
tunacode/cli/main.py,sha256=
|
|
11
|
-
tunacode/cli/repl.py,sha256=
|
|
12
|
-
tunacode/cli/textual_app.py,sha256=
|
|
13
|
-
tunacode/cli/textual_bridge.py,sha256=
|
|
9
|
+
tunacode/cli/commands.py,sha256=VblfttlJsl66pZWy-r3m7grEtHle55jo2wcXI38Anuw,30798
|
|
10
|
+
tunacode/cli/main.py,sha256=jQ58azaubmqQQHEogeoquVEL-98d_7HaU1_2FcTlOCw,2406
|
|
11
|
+
tunacode/cli/repl.py,sha256=sXtRHYameAlMjlee82ix8P2JjRyWLrdFfHwxfaMKPb8,13722
|
|
12
|
+
tunacode/cli/textual_app.py,sha256=14-Nt0IIETmyHBrNn9uwSF3EwCcutwTp6gdoKgNm0sY,12593
|
|
13
|
+
tunacode/cli/textual_bridge.py,sha256=CTuf5Yjg5occQa7whyopS_erbJdS2UpWqaX_TVJ2D2A,6140
|
|
14
14
|
tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
|
|
15
15
|
tunacode/configuration/defaults.py,sha256=7UdHP50NmnZWlx0f1PGV4JZIpmQem191vWisGky6AVA,688
|
|
16
16
|
tunacode/configuration/models.py,sha256=XPobkLM_TzKTuMIWhK-svJfGRGFT9r2LhKEM6rv6QHk,3756
|
|
@@ -19,41 +19,42 @@ tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
19
19
|
tunacode/core/state.py,sha256=n1claG-gVVDMBCCS8cDmgas4XbKLJJwKRc-8CtXeTS8,1376
|
|
20
20
|
tunacode/core/tool_handler.py,sha256=OKx7jM8pml6pSEnoARu33_uBY8awJBqvhbVeBn6T4ow,1804
|
|
21
21
|
tunacode/core/agents/__init__.py,sha256=TiXwymGRNMuOqQaRLpNCAt7bZArg8rkadIRs4Nw21SQ,275
|
|
22
|
-
tunacode/core/agents/main.py,sha256=
|
|
22
|
+
tunacode/core/agents/main.py,sha256=mqKeLJ2ywh2rPbkJtawgHwjJ0C4MrKpFrUDq1AAYtbs,14667
|
|
23
23
|
tunacode/core/agents/orchestrator.py,sha256=5CjHpyB1FlHe2-xJXM1M9ruaFu9gJ_9Izev4mlOOPrw,3578
|
|
24
24
|
tunacode/core/agents/planner_schema.py,sha256=pu2ehQVALjiJ5HJD7EN6xuZHCknsrXO9z0xHuVdlKW8,345
|
|
25
25
|
tunacode/core/agents/readonly.py,sha256=NOPfqPWu53fJy77k5uqwKWmZ6yzqnDOZpBeQjGy0AG8,1624
|
|
26
26
|
tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
27
|
tunacode/core/background/manager.py,sha256=rJdl3eDLTQwjbT7VhxXcJbZopCNR3M8ZGMbmeVnwwMc,1126
|
|
28
28
|
tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
tunacode/core/llm/planner.py,sha256=
|
|
29
|
+
tunacode/core/llm/planner.py,sha256=G1oxRFynYisWspcWr6KvVuiWHmElozhhVds6Wj4yrLk,2111
|
|
30
30
|
tunacode/core/setup/__init__.py,sha256=lzdpY6rIGf9DDlDBDGFvQZaSOQeFsNglHbkpq1-GtU8,376
|
|
31
31
|
tunacode/core/setup/agent_setup.py,sha256=trELO8cPnWo36BBnYmXDEnDPdhBg0p-VLnx9A8hSSSQ,1401
|
|
32
32
|
tunacode/core/setup/base.py,sha256=cbyT2-xK2mWgH4EO17VfM_OM2bj0kT895NW2jSXbe3c,968
|
|
33
|
-
tunacode/core/setup/config_setup.py,sha256=
|
|
33
|
+
tunacode/core/setup/config_setup.py,sha256=A1MEbkZq2FvVg9FNlLD9_JO_vlr0ixP-6Ay0-2W7VvQ,14330
|
|
34
34
|
tunacode/core/setup/coordinator.py,sha256=oVTN2xIeJERXitVJpkIk9tDGLs1D1bxIRmaogJwZJFI,2049
|
|
35
35
|
tunacode/core/setup/environment_setup.py,sha256=n3IrObKEynHZSwtUJ1FddMg2C4sHz7ca42awemImV8s,2225
|
|
36
36
|
tunacode/core/setup/git_safety_setup.py,sha256=T7hwIf3u3Tq3QtIdUAfuHI6vclMfm2Sqcml5l6x02oA,6799
|
|
37
|
+
tunacode/prompts/system.md,sha256=fgGwjFABDOi97AlZFwxvYhj4K4i0RuVfQDlTalMnAs4,3204
|
|
37
38
|
tunacode/prompts/system.txt,sha256=VEt0PKne0AzHbFkA4IuyCYQkX6AInWeYZOL4NyeJHNw,6939
|
|
38
39
|
tunacode/services/__init__.py,sha256=w_E8QK6RnvKSvU866eDe8BCRV26rAm4d3R-Yg06OWCU,19
|
|
39
40
|
tunacode/services/mcp.py,sha256=R48X73KQjQ9vwhBrtbWHSBl-4K99QXmbIhh5J_1Gezo,3046
|
|
40
|
-
tunacode/tools/__init__.py,sha256=
|
|
41
|
+
tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
|
|
41
42
|
tunacode/tools/base.py,sha256=TF71ZE66-W-7GLY8QcPpPJ5CVjod6FHL1caBOTCssvU,7044
|
|
42
43
|
tunacode/tools/bash.py,sha256=mgZqugfDFevZ4BETuUv90pzXvtq7qKGUGFiuDxzmytk,8766
|
|
43
|
-
tunacode/tools/grep.py,sha256=
|
|
44
|
+
tunacode/tools/grep.py,sha256=N0Iu5MuSAVGBueu6PoE4Pt1x3oMIlX5aaZyejQwTlU8,26492
|
|
44
45
|
tunacode/tools/read_file.py,sha256=Cz1-7sdQwOdaqkVvkVpORiBdNtncCVlP9e9cu37ya80,2988
|
|
45
46
|
tunacode/tools/run_command.py,sha256=kYg_Re397OmZdKtUSjpNfYYNDBjd0vsS1xMK0yP181I,3776
|
|
46
47
|
tunacode/tools/update_file.py,sha256=bW1MhTzRjBDjJzqQ6A1yCVEbkr1oIqtEC8uqcg_rfY4,3957
|
|
47
48
|
tunacode/tools/write_file.py,sha256=prL6u8XOi9ZyPU-YNlG9YMLbSLrDJXDRuDX73ncXh-k,2699
|
|
48
49
|
tunacode/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
|
|
49
|
-
tunacode/ui/completers.py,sha256=
|
|
50
|
+
tunacode/ui/completers.py,sha256=Jx1zyCESwdm_4ZopvCBtb0bCJF-bRy8aBWG2yhPQtDc,4878
|
|
50
51
|
tunacode/ui/console.py,sha256=LTEWQLdRP0JkhbEPIHIDrSX3ZZld9iJI2aZ3-eGliOc,1930
|
|
51
52
|
tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
|
|
52
53
|
tunacode/ui/decorators.py,sha256=e2KM-_pI5EKHa2M045IjUe4rPkTboxaKHXJT0K3461g,1914
|
|
53
|
-
tunacode/ui/input.py,sha256=
|
|
54
|
+
tunacode/ui/input.py,sha256=6LlEwKIXYXusNDI2PD0DDjRymQgu5mf2v06TsHbUln0,2957
|
|
54
55
|
tunacode/ui/keybindings.py,sha256=h0MlD73CW_3i2dQzb9EFSPkqy0raZ_isgjxUiA9u6ts,691
|
|
55
|
-
tunacode/ui/lexers.py,sha256=
|
|
56
|
-
tunacode/ui/output.py,sha256=
|
|
56
|
+
tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
|
|
57
|
+
tunacode/ui/output.py,sha256=gx9hsTdG5AOOiOwkxkmFing4oxo_rhps0D9vuz3z1YM,4497
|
|
57
58
|
tunacode/ui/panels.py,sha256=_8B1rGOhPnSLekGM4ZzDJw-dCuaPeacsaCmmCggqxwE,5950
|
|
58
59
|
tunacode/ui/prompt_manager.py,sha256=U2cntB34vm-YwOj3gzFRUK362zccrz8pigQfpxr5sv8,4650
|
|
59
60
|
tunacode/ui/tool_ui.py,sha256=S5-k1HwRlSqiQ8shGQ_QYGXQbuzb6Pg7u3CTqZwffdQ,6533
|
|
@@ -67,9 +68,9 @@ tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
|
|
|
67
68
|
tunacode/utils/system.py,sha256=FSoibTIH0eybs4oNzbYyufIiV6gb77QaeY2yGqW39AY,11381
|
|
68
69
|
tunacode/utils/text_utils.py,sha256=B9M1cuLTm_SSsr15WNHF6j7WdLWPvWzKZV0Lvfgdbjg,2458
|
|
69
70
|
tunacode/utils/user_configuration.py,sha256=IGvUH37wWtZ4M5xpukZEWYhtuKKyKcl6DaeObGXdleU,2610
|
|
70
|
-
tunacode_cli-0.0.
|
|
71
|
-
tunacode_cli-0.0.
|
|
72
|
-
tunacode_cli-0.0.
|
|
73
|
-
tunacode_cli-0.0.
|
|
74
|
-
tunacode_cli-0.0.
|
|
75
|
-
tunacode_cli-0.0.
|
|
71
|
+
tunacode_cli-0.0.24.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
|
|
72
|
+
tunacode_cli-0.0.24.dist-info/METADATA,sha256=UGjot1qmeyYwcRbVHqsruMwLOP0YrbgTsW-flg2Yde4,18937
|
|
73
|
+
tunacode_cli-0.0.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
74
|
+
tunacode_cli-0.0.24.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
|
|
75
|
+
tunacode_cli-0.0.24.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
|
|
76
|
+
tunacode_cli-0.0.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|