tunacode-cli 0.0.17__tar.gz → 0.0.19__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.
Potentially problematic release.
This version of tunacode-cli might be problematic. Click here for more details.
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/PKG-INFO +68 -11
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/README.md +67 -10
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/pyproject.toml +1 -1
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/commands.py +73 -41
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/main.py +29 -26
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/repl.py +91 -37
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/textual_app.py +69 -66
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/textual_bridge.py +33 -32
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/configuration/settings.py +2 -9
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/constants.py +2 -4
- tunacode_cli-0.0.19/src/tunacode/core/agents/__init__.py +12 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/agents/main.py +89 -63
- tunacode_cli-0.0.19/src/tunacode/core/agents/orchestrator.py +99 -0
- tunacode_cli-0.0.19/src/tunacode/core/agents/planner_schema.py +9 -0
- tunacode_cli-0.0.19/src/tunacode/core/agents/readonly.py +51 -0
- tunacode_cli-0.0.19/src/tunacode/core/background/manager.py +36 -0
- tunacode_cli-0.0.19/src/tunacode/core/llm/planner.py +63 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/config_setup.py +79 -44
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/coordinator.py +20 -13
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/git_safety_setup.py +35 -49
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/state.py +2 -9
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/exceptions.py +0 -2
- tunacode_cli-0.0.19/src/tunacode/prompts/system.txt +203 -0
- tunacode_cli-0.0.19/src/tunacode/tools/__init__.py +10 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/base.py +1 -1
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/bash.py +5 -5
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/grep.py +210 -250
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/read_file.py +2 -8
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/run_command.py +4 -11
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/update_file.py +2 -6
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/completers.py +32 -31
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/console.py +3 -3
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/input.py +8 -5
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/keybindings.py +1 -3
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/lexers.py +16 -16
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/output.py +2 -2
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/panels.py +8 -8
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/prompt_manager.py +19 -7
- tunacode_cli-0.0.19/src/tunacode/utils/__init__.py +0 -0
- tunacode_cli-0.0.19/src/tunacode/utils/import_cache.py +11 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/user_configuration.py +24 -2
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/PKG-INFO +68 -11
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/SOURCES.txt +19 -1
- tunacode_cli-0.0.19/tests/test_architect_integration.py +120 -0
- tunacode_cli-0.0.19/tests/test_architect_simple.py +125 -0
- tunacode_cli-0.0.19/tests/test_background_manager.py +26 -0
- tunacode_cli-0.0.19/tests/test_fast_glob_search.py +191 -0
- tunacode_cli-0.0.19/tests/test_file_reference_expansion.py +158 -0
- tunacode_cli-0.0.19/tests/test_json_tool_parsing.py +207 -0
- tunacode_cli-0.0.19/tests/test_orchestrator_file_references.py +146 -0
- tunacode_cli-0.0.19/tests/test_orchestrator_import.py +22 -0
- tunacode_cli-0.0.19/tests/test_orchestrator_planning_visibility.py +56 -0
- tunacode_cli-0.0.19/tests/test_react_thoughts.py +149 -0
- tunacode_cli-0.0.19/tests/test_update_command.py +47 -0
- tunacode_cli-0.0.17/src/tunacode/prompts/system.txt +0 -93
- tunacode_cli-0.0.17/src/tunacode/tools/__init__.py +0 -1
- tunacode_cli-0.0.17/tests/test_escape_mechanism.py +0 -184
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/LICENSE +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/setup.cfg +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/setup.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/cli/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/configuration/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/configuration/defaults.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/configuration/models.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/context.py +1 -1
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/__init__.py +0 -0
- {tunacode_cli-0.0.17/src/tunacode/core/agents → tunacode_cli-0.0.19/src/tunacode/core/background}/__init__.py +0 -0
- {tunacode_cli-0.0.17/src/tunacode/utils → tunacode_cli-0.0.19/src/tunacode/core/llm}/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/agent_setup.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/base.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/setup/environment_setup.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/core/tool_handler.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/py.typed +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/services/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/services/mcp.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/setup.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/tools/write_file.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/types.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/__init__.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/constants.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/decorators.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/tool_ui.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/ui/validators.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/bm25.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/diff_utils.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/file_utils.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/ripgrep.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/system.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode/utils/text_utils.py +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/requires.txt +0 -0
- {tunacode_cli-0.0.17 → tunacode_cli-0.0.19}/src/tunacode_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunacode-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.19
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -58,14 +58,20 @@ Dynamic: license-file
|
|
|
58
58
|
|
|
59
59
|
---
|
|
60
60
|
|
|
61
|
-
### Recent Updates (v0.0.
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
61
|
+
### Recent Updates (v0.0.18)
|
|
62
|
+
|
|
63
|
+
- **Advanced Agent Orchestration**: New orchestrator system for complex multi-step tasks with planning visibility
|
|
64
|
+
- **Background Task Manager**: Asynchronous background processing for long-running operations
|
|
65
|
+
- **Read-Only Agent**: Specialized agent for safe codebase exploration without modification risks
|
|
66
|
+
- **Planning Transparency**: See the AI's planning process before execution with detailed task breakdowns
|
|
67
|
+
- **Shell Command Support**: Execute shell commands directly with `!command` or open interactive shell with `!`
|
|
68
|
+
- **Enhanced Bash Tool**: Advanced bash execution with timeouts, working directory, and environment variables
|
|
69
|
+
- **JSON Tool Parsing Fallback**: Automatic recovery when API providers fail with structured tool calling
|
|
70
|
+
- **Enhanced Reliability**: Fixed parameter naming issues that caused tool schema errors
|
|
71
|
+
- **Configuration Management**: New `/refresh` command to reload config without restart
|
|
72
|
+
- **Improved ReAct Reasoning**: Enhanced iteration limits (now defaults to 20) and better thought processing
|
|
73
|
+
- **New Debug Commands**: `/parsetools` for manual JSON parsing, `/iterations` for controlling reasoning depth
|
|
74
|
+
- **Better Error Recovery**: Multiple fallback mechanisms for various failure scenarios
|
|
69
75
|
|
|
70
76
|
### Core Features
|
|
71
77
|
|
|
@@ -84,6 +90,7 @@ Dynamic: license-file
|
|
|
84
90
|
### **Developer Tools**
|
|
85
91
|
|
|
86
92
|
- 6 core tools: bash, grep, read_file, write_file, update_file, run_command
|
|
93
|
+
- Direct shell command execution with `!` prefix
|
|
87
94
|
- MCP (Model Context Protocol) support
|
|
88
95
|
- File operation confirmations with diffs
|
|
89
96
|
- Per-project context guides (TUNACODE.md)
|
|
@@ -284,6 +291,8 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
|
|
|
284
291
|
| `/model <provider:name> default` | Set default model |
|
|
285
292
|
| `/branch <name>` | Create and switch Git branch |
|
|
286
293
|
| `/dump` | Show message history (debug) |
|
|
294
|
+
| `!<command>` | Run shell command |
|
|
295
|
+
| `!` | Open interactive shell |
|
|
287
296
|
| `exit` | Exit application |
|
|
288
297
|
|
|
289
298
|
### Debug & Recovery Commands
|
|
@@ -298,6 +307,42 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
|
|
|
298
307
|
|
|
299
308
|
---
|
|
300
309
|
|
|
310
|
+
## Available Tools
|
|
311
|
+
|
|
312
|
+
### Bash Tool
|
|
313
|
+
The enhanced bash tool provides advanced shell command execution with safety features:
|
|
314
|
+
|
|
315
|
+
- **Working Directory Support**: Execute commands in specific directories
|
|
316
|
+
- **Environment Variables**: Set custom environment variables for commands
|
|
317
|
+
- **Timeout Control**: Configurable timeouts (1-300 seconds) to prevent hanging
|
|
318
|
+
- **Output Capture**: Full stdout/stderr capture with truncation for large outputs
|
|
319
|
+
- **Safety Checks**: Warns about potentially destructive commands
|
|
320
|
+
- **Error Guidance**: Helpful error messages for common issues (command not found, permission denied, etc.)
|
|
321
|
+
|
|
322
|
+
**Example usage by the AI:**
|
|
323
|
+
```python
|
|
324
|
+
# Simple command
|
|
325
|
+
await bash("ls -la")
|
|
326
|
+
|
|
327
|
+
# With working directory
|
|
328
|
+
await bash("npm install", cwd="/path/to/project")
|
|
329
|
+
|
|
330
|
+
# With timeout for long operations
|
|
331
|
+
await bash("npm run build", timeout=120)
|
|
332
|
+
|
|
333
|
+
# With environment variables
|
|
334
|
+
await bash("python script.py", env={"API_KEY": "secret"})
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Other Core Tools
|
|
338
|
+
- **grep**: Fast parallel content search across files
|
|
339
|
+
- **read_file**: Read file contents with line numbers
|
|
340
|
+
- **write_file**: Create new files (fails if file exists)
|
|
341
|
+
- **update_file**: Modify existing files with precise replacements
|
|
342
|
+
- **run_command**: Basic command execution (simpler than bash)
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
301
346
|
## Reliability Features
|
|
302
347
|
|
|
303
348
|
### JSON Tool Parsing Fallback
|
|
@@ -360,7 +405,14 @@ src/tunacode/
|
|
|
360
405
|
│
|
|
361
406
|
├── core/ # Core Application Logic
|
|
362
407
|
│ ├── agents/ # AI Agent System
|
|
363
|
-
│ │
|
|
408
|
+
│ │ ├── main.py # Primary agent implementation (pydantic-ai)
|
|
409
|
+
│ │ ├── orchestrator.py # Complex task orchestration and planning
|
|
410
|
+
│ │ ├── planner_schema.py # Planning data models
|
|
411
|
+
│ │ └── readonly.py # Read-only agent for safe exploration
|
|
412
|
+
│ ├── background/ # Background Task Management
|
|
413
|
+
│ │ └── manager.py # Async background task execution
|
|
414
|
+
│ ├── llm/ # LLM Integration
|
|
415
|
+
│ │ └── planner.py # LLM-based task planning
|
|
364
416
|
│ ├── setup/ # Application Setup & Initialization
|
|
365
417
|
│ │ ├── agent_setup.py # Agent configuration
|
|
366
418
|
│ │ ├── base.py # Setup step base class
|
|
@@ -409,7 +461,7 @@ src/tunacode/
|
|
|
409
461
|
├── exceptions.py # Custom exceptions
|
|
410
462
|
├── types.py # Type definitions
|
|
411
463
|
└── prompts/
|
|
412
|
-
└── system.
|
|
464
|
+
└── system.md # System prompts for AI agent
|
|
413
465
|
```
|
|
414
466
|
|
|
415
467
|
### Key Components
|
|
@@ -418,6 +470,8 @@ src/tunacode/
|
|
|
418
470
|
| -------------------- | ------------------------ | ------------------------------- |
|
|
419
471
|
| **CLI Layer** | Command parsing and REPL | `cli/main.py`, `cli/repl.py` |
|
|
420
472
|
| **Agent System** | AI-powered assistance | `core/agents/main.py` |
|
|
473
|
+
| **Orchestrator** | Complex task planning | `core/agents/orchestrator.py` |
|
|
474
|
+
| **Background Tasks** | Async task execution | `core/background/manager.py` |
|
|
421
475
|
| **Tool System** | File/command operations | `tools/*.py` |
|
|
422
476
|
| **State Management** | Session state tracking | `core/state.py` |
|
|
423
477
|
| **UI Framework** | Rich terminal interface | `ui/output.py`, `ui/console.py` |
|
|
@@ -482,6 +536,9 @@ While TunaCode builds on the foundation of sidekick-cli, we've made several arch
|
|
|
482
536
|
|
|
483
537
|
- **JSON Tool Parsing Fallback**: Added fallback parsing for when API providers fail with structured tool calling
|
|
484
538
|
- **Parallel Search Tools**: New `bash` and `grep` tools with parallel execution for codebase navigation
|
|
539
|
+
- **Agent Orchestration**: Advanced orchestrator for complex multi-step tasks with planning transparency
|
|
540
|
+
- **Background Processing**: Asynchronous task manager for long-running operations
|
|
541
|
+
- **Read-Only Agent**: Safe exploration mode that prevents accidental modifications
|
|
485
542
|
- **ReAct Reasoning**: Implemented ReAct (Reasoning + Acting) patterns with configurable iteration limits
|
|
486
543
|
- **Dynamic Configuration**: Added `/refresh` command and modified configuration management
|
|
487
544
|
- **Safety Changes**: Removed automatic git commits and `/undo` command - requires explicit git usage
|
|
@@ -22,14 +22,20 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
-
### Recent Updates (v0.0.
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
25
|
+
### Recent Updates (v0.0.18)
|
|
26
|
+
|
|
27
|
+
- **Advanced Agent Orchestration**: New orchestrator system for complex multi-step tasks with planning visibility
|
|
28
|
+
- **Background Task Manager**: Asynchronous background processing for long-running operations
|
|
29
|
+
- **Read-Only Agent**: Specialized agent for safe codebase exploration without modification risks
|
|
30
|
+
- **Planning Transparency**: See the AI's planning process before execution with detailed task breakdowns
|
|
31
|
+
- **Shell Command Support**: Execute shell commands directly with `!command` or open interactive shell with `!`
|
|
32
|
+
- **Enhanced Bash Tool**: Advanced bash execution with timeouts, working directory, and environment variables
|
|
33
|
+
- **JSON Tool Parsing Fallback**: Automatic recovery when API providers fail with structured tool calling
|
|
34
|
+
- **Enhanced Reliability**: Fixed parameter naming issues that caused tool schema errors
|
|
35
|
+
- **Configuration Management**: New `/refresh` command to reload config without restart
|
|
36
|
+
- **Improved ReAct Reasoning**: Enhanced iteration limits (now defaults to 20) and better thought processing
|
|
37
|
+
- **New Debug Commands**: `/parsetools` for manual JSON parsing, `/iterations` for controlling reasoning depth
|
|
38
|
+
- **Better Error Recovery**: Multiple fallback mechanisms for various failure scenarios
|
|
33
39
|
|
|
34
40
|
### Core Features
|
|
35
41
|
|
|
@@ -48,6 +54,7 @@
|
|
|
48
54
|
### **Developer Tools**
|
|
49
55
|
|
|
50
56
|
- 6 core tools: bash, grep, read_file, write_file, update_file, run_command
|
|
57
|
+
- Direct shell command execution with `!` prefix
|
|
51
58
|
- MCP (Model Context Protocol) support
|
|
52
59
|
- File operation confirmations with diffs
|
|
53
60
|
- Per-project context guides (TUNACODE.md)
|
|
@@ -248,6 +255,8 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
|
|
|
248
255
|
| `/model <provider:name> default` | Set default model |
|
|
249
256
|
| `/branch <name>` | Create and switch Git branch |
|
|
250
257
|
| `/dump` | Show message history (debug) |
|
|
258
|
+
| `!<command>` | Run shell command |
|
|
259
|
+
| `!` | Open interactive shell |
|
|
251
260
|
| `exit` | Exit application |
|
|
252
261
|
|
|
253
262
|
### Debug & Recovery Commands
|
|
@@ -262,6 +271,42 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
|
|
|
262
271
|
|
|
263
272
|
---
|
|
264
273
|
|
|
274
|
+
## Available Tools
|
|
275
|
+
|
|
276
|
+
### Bash Tool
|
|
277
|
+
The enhanced bash tool provides advanced shell command execution with safety features:
|
|
278
|
+
|
|
279
|
+
- **Working Directory Support**: Execute commands in specific directories
|
|
280
|
+
- **Environment Variables**: Set custom environment variables for commands
|
|
281
|
+
- **Timeout Control**: Configurable timeouts (1-300 seconds) to prevent hanging
|
|
282
|
+
- **Output Capture**: Full stdout/stderr capture with truncation for large outputs
|
|
283
|
+
- **Safety Checks**: Warns about potentially destructive commands
|
|
284
|
+
- **Error Guidance**: Helpful error messages for common issues (command not found, permission denied, etc.)
|
|
285
|
+
|
|
286
|
+
**Example usage by the AI:**
|
|
287
|
+
```python
|
|
288
|
+
# Simple command
|
|
289
|
+
await bash("ls -la")
|
|
290
|
+
|
|
291
|
+
# With working directory
|
|
292
|
+
await bash("npm install", cwd="/path/to/project")
|
|
293
|
+
|
|
294
|
+
# With timeout for long operations
|
|
295
|
+
await bash("npm run build", timeout=120)
|
|
296
|
+
|
|
297
|
+
# With environment variables
|
|
298
|
+
await bash("python script.py", env={"API_KEY": "secret"})
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Other Core Tools
|
|
302
|
+
- **grep**: Fast parallel content search across files
|
|
303
|
+
- **read_file**: Read file contents with line numbers
|
|
304
|
+
- **write_file**: Create new files (fails if file exists)
|
|
305
|
+
- **update_file**: Modify existing files with precise replacements
|
|
306
|
+
- **run_command**: Basic command execution (simpler than bash)
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
265
310
|
## Reliability Features
|
|
266
311
|
|
|
267
312
|
### JSON Tool Parsing Fallback
|
|
@@ -324,7 +369,14 @@ src/tunacode/
|
|
|
324
369
|
│
|
|
325
370
|
├── core/ # Core Application Logic
|
|
326
371
|
│ ├── agents/ # AI Agent System
|
|
327
|
-
│ │
|
|
372
|
+
│ │ ├── main.py # Primary agent implementation (pydantic-ai)
|
|
373
|
+
│ │ ├── orchestrator.py # Complex task orchestration and planning
|
|
374
|
+
│ │ ├── planner_schema.py # Planning data models
|
|
375
|
+
│ │ └── readonly.py # Read-only agent for safe exploration
|
|
376
|
+
│ ├── background/ # Background Task Management
|
|
377
|
+
│ │ └── manager.py # Async background task execution
|
|
378
|
+
│ ├── llm/ # LLM Integration
|
|
379
|
+
│ │ └── planner.py # LLM-based task planning
|
|
328
380
|
│ ├── setup/ # Application Setup & Initialization
|
|
329
381
|
│ │ ├── agent_setup.py # Agent configuration
|
|
330
382
|
│ │ ├── base.py # Setup step base class
|
|
@@ -373,7 +425,7 @@ src/tunacode/
|
|
|
373
425
|
├── exceptions.py # Custom exceptions
|
|
374
426
|
├── types.py # Type definitions
|
|
375
427
|
└── prompts/
|
|
376
|
-
└── system.
|
|
428
|
+
└── system.md # System prompts for AI agent
|
|
377
429
|
```
|
|
378
430
|
|
|
379
431
|
### Key Components
|
|
@@ -382,6 +434,8 @@ src/tunacode/
|
|
|
382
434
|
| -------------------- | ------------------------ | ------------------------------- |
|
|
383
435
|
| **CLI Layer** | Command parsing and REPL | `cli/main.py`, `cli/repl.py` |
|
|
384
436
|
| **Agent System** | AI-powered assistance | `core/agents/main.py` |
|
|
437
|
+
| **Orchestrator** | Complex task planning | `core/agents/orchestrator.py` |
|
|
438
|
+
| **Background Tasks** | Async task execution | `core/background/manager.py` |
|
|
385
439
|
| **Tool System** | File/command operations | `tools/*.py` |
|
|
386
440
|
| **State Management** | Session state tracking | `core/state.py` |
|
|
387
441
|
| **UI Framework** | Rich terminal interface | `ui/output.py`, `ui/console.py` |
|
|
@@ -446,6 +500,9 @@ While TunaCode builds on the foundation of sidekick-cli, we've made several arch
|
|
|
446
500
|
|
|
447
501
|
- **JSON Tool Parsing Fallback**: Added fallback parsing for when API providers fail with structured tool calling
|
|
448
502
|
- **Parallel Search Tools**: New `bash` and `grep` tools with parallel execution for codebase navigation
|
|
503
|
+
- **Agent Orchestration**: Advanced orchestrator for complex multi-step tasks with planning transparency
|
|
504
|
+
- **Background Processing**: Asynchronous task manager for long-running operations
|
|
505
|
+
- **Read-Only Agent**: Safe exploration mode that prevents accidental modifications
|
|
449
506
|
- **ReAct Reasoning**: Implemented ReAct (Reasoning + Acting) patterns with configurable iteration limits
|
|
450
507
|
- **Dynamic Configuration**: Added `/refresh` command and modified configuration management
|
|
451
508
|
- **Safety Changes**: Removed automatic git commits and `/undo` command - requires explicit git usage
|
|
@@ -6,7 +6,6 @@ from enum import Enum
|
|
|
6
6
|
from typing import Any, Dict, List, Optional, Type
|
|
7
7
|
|
|
8
8
|
from .. import utils
|
|
9
|
-
from ..configuration.models import ModelRegistry
|
|
10
9
|
from ..exceptions import ValidationError
|
|
11
10
|
from ..types import CommandArgs, CommandContext, CommandResult, ProcessRequestCallback
|
|
12
11
|
from ..ui import console as ui
|
|
@@ -116,9 +115,9 @@ class YoloCommand(SimpleCommand):
|
|
|
116
115
|
state = context.state_manager.session
|
|
117
116
|
state.yolo = not state.yolo
|
|
118
117
|
if state.yolo:
|
|
119
|
-
await ui.success("
|
|
118
|
+
await ui.success("All tools are now active ⚡ Please proceed with caution.\n")
|
|
120
119
|
else:
|
|
121
|
-
await ui.info("
|
|
120
|
+
await ui.info("Tool confirmations re-enabled for safety.\n")
|
|
122
121
|
|
|
123
122
|
|
|
124
123
|
class DumpCommand(SimpleCommand):
|
|
@@ -168,6 +167,39 @@ class ThoughtsCommand(SimpleCommand):
|
|
|
168
167
|
await ui.success(f"Thought display {status}")
|
|
169
168
|
|
|
170
169
|
|
|
170
|
+
class ArchitectCommand(SimpleCommand):
|
|
171
|
+
"""Toggle architect mode for task planning and orchestration."""
|
|
172
|
+
|
|
173
|
+
def __init__(self):
|
|
174
|
+
super().__init__(
|
|
175
|
+
CommandSpec(
|
|
176
|
+
name="architect",
|
|
177
|
+
aliases=["/architect"],
|
|
178
|
+
description="Toggle architect mode (task planning & orchestration)",
|
|
179
|
+
category=CommandCategory.DEBUG,
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
184
|
+
state = context.state_manager.session
|
|
185
|
+
if args:
|
|
186
|
+
arg = args[0].lower()
|
|
187
|
+
if arg in {"on", "1", "true"}:
|
|
188
|
+
state.architect_mode = True
|
|
189
|
+
elif arg in {"off", "0", "false"}:
|
|
190
|
+
state.architect_mode = False
|
|
191
|
+
else:
|
|
192
|
+
await ui.error("Usage: /architect [on|off]")
|
|
193
|
+
return
|
|
194
|
+
else:
|
|
195
|
+
state.architect_mode = not getattr(state, 'architect_mode', False)
|
|
196
|
+
status = "ON" if state.architect_mode else "OFF"
|
|
197
|
+
if state.architect_mode:
|
|
198
|
+
await ui.success(f"Architect mode {status} - Requests will be planned before execution")
|
|
199
|
+
else:
|
|
200
|
+
await ui.success(f"Architect mode {status} - Using direct execution")
|
|
201
|
+
|
|
202
|
+
|
|
171
203
|
class IterationsCommand(SimpleCommand):
|
|
172
204
|
"""Configure maximum agent iterations for ReAct reasoning."""
|
|
173
205
|
|
|
@@ -189,12 +221,12 @@ class IterationsCommand(SimpleCommand):
|
|
|
189
221
|
if new_limit < 1 or new_limit > 50:
|
|
190
222
|
await ui.error("Iterations must be between 1 and 50")
|
|
191
223
|
return
|
|
192
|
-
|
|
224
|
+
|
|
193
225
|
# Update the user config
|
|
194
226
|
if "settings" not in state.user_config:
|
|
195
227
|
state.user_config["settings"] = {}
|
|
196
228
|
state.user_config["settings"]["max_iterations"] = new_limit
|
|
197
|
-
|
|
229
|
+
|
|
198
230
|
await ui.success(f"Maximum iterations set to {new_limit}")
|
|
199
231
|
await ui.muted("Higher values allow more complex reasoning but may be slower")
|
|
200
232
|
except ValueError:
|
|
@@ -221,8 +253,9 @@ class ClearCommand(SimpleCommand):
|
|
|
221
253
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
222
254
|
# Patch any orphaned tool calls before clearing
|
|
223
255
|
from tunacode.core.agents.main import patch_tool_messages
|
|
256
|
+
|
|
224
257
|
patch_tool_messages("Conversation cleared", context.state_manager)
|
|
225
|
-
|
|
258
|
+
|
|
226
259
|
await ui.clear()
|
|
227
260
|
context.state_manager.session.messages = []
|
|
228
261
|
await ui.success("Message history cleared")
|
|
@@ -243,17 +276,17 @@ class FixCommand(SimpleCommand):
|
|
|
243
276
|
|
|
244
277
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
245
278
|
from tunacode.core.agents.main import patch_tool_messages
|
|
246
|
-
|
|
279
|
+
|
|
247
280
|
# Count current messages
|
|
248
281
|
before_count = len(context.state_manager.session.messages)
|
|
249
|
-
|
|
282
|
+
|
|
250
283
|
# Patch orphaned tool calls
|
|
251
284
|
patch_tool_messages("Tool call resolved by /fix command", context.state_manager)
|
|
252
|
-
|
|
285
|
+
|
|
253
286
|
# Count after patching
|
|
254
287
|
after_count = len(context.state_manager.session.messages)
|
|
255
288
|
patched_count = after_count - before_count
|
|
256
|
-
|
|
289
|
+
|
|
257
290
|
if patched_count > 0:
|
|
258
291
|
await ui.success(f"Fixed {patched_count} orphaned tool call(s)")
|
|
259
292
|
await ui.muted("You can now continue the conversation normally")
|
|
@@ -269,36 +302,37 @@ class ParseToolsCommand(SimpleCommand):
|
|
|
269
302
|
CommandSpec(
|
|
270
303
|
name="parsetools",
|
|
271
304
|
aliases=["/parsetools"],
|
|
272
|
-
description=
|
|
305
|
+
description=(
|
|
306
|
+
"Parse JSON tool calls from last response when structured calling fails"
|
|
307
|
+
),
|
|
273
308
|
category=CommandCategory.DEBUG,
|
|
274
309
|
)
|
|
275
310
|
)
|
|
276
311
|
|
|
277
312
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
278
313
|
from tunacode.core.agents.main import extract_and_execute_tool_calls
|
|
279
|
-
|
|
314
|
+
|
|
280
315
|
# Find the last model response in messages
|
|
281
316
|
messages = context.state_manager.session.messages
|
|
282
317
|
if not messages:
|
|
283
318
|
await ui.error("No message history found")
|
|
284
319
|
return
|
|
285
|
-
|
|
320
|
+
|
|
286
321
|
# Look for the most recent response with text content
|
|
287
322
|
found_content = False
|
|
288
323
|
for msg in reversed(messages):
|
|
289
|
-
if hasattr(msg,
|
|
324
|
+
if hasattr(msg, "parts"):
|
|
290
325
|
for part in msg.parts:
|
|
291
|
-
if hasattr(part,
|
|
326
|
+
if hasattr(part, "content") and isinstance(part.content, str):
|
|
292
327
|
# Create tool callback
|
|
293
328
|
from tunacode.cli.repl import _tool_handler
|
|
329
|
+
|
|
294
330
|
def tool_callback_with_state(part, node):
|
|
295
331
|
return _tool_handler(part, node, context.state_manager)
|
|
296
|
-
|
|
332
|
+
|
|
297
333
|
try:
|
|
298
334
|
await extract_and_execute_tool_calls(
|
|
299
|
-
part.content,
|
|
300
|
-
tool_callback_with_state,
|
|
301
|
-
context.state_manager
|
|
335
|
+
part.content, tool_callback_with_state, context.state_manager
|
|
302
336
|
)
|
|
303
337
|
await ui.success("JSON tool parsing completed")
|
|
304
338
|
found_content = True
|
|
@@ -306,7 +340,7 @@ class ParseToolsCommand(SimpleCommand):
|
|
|
306
340
|
except Exception as e:
|
|
307
341
|
await ui.error(f"Failed to parse tools: {str(e)}")
|
|
308
342
|
return
|
|
309
|
-
|
|
343
|
+
|
|
310
344
|
if not found_content:
|
|
311
345
|
await ui.error("No parseable content found in recent messages")
|
|
312
346
|
|
|
@@ -326,7 +360,7 @@ class RefreshConfigCommand(SimpleCommand):
|
|
|
326
360
|
|
|
327
361
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
328
362
|
from tunacode.configuration.defaults import DEFAULT_USER_CONFIG
|
|
329
|
-
|
|
363
|
+
|
|
330
364
|
# Update current session config with latest defaults
|
|
331
365
|
for key, value in DEFAULT_USER_CONFIG.items():
|
|
332
366
|
if key not in context.state_manager.session.user_config:
|
|
@@ -336,9 +370,11 @@ class RefreshConfigCommand(SimpleCommand):
|
|
|
336
370
|
for subkey, subvalue in value.items():
|
|
337
371
|
if subkey not in context.state_manager.session.user_config[key]:
|
|
338
372
|
context.state_manager.session.user_config[key][subkey] = subvalue
|
|
339
|
-
|
|
373
|
+
|
|
340
374
|
# Show updated max_iterations
|
|
341
|
-
max_iterations = context.state_manager.session.user_config.get("settings", {}).get(
|
|
375
|
+
max_iterations = context.state_manager.session.user_config.get("settings", {}).get(
|
|
376
|
+
"max_iterations", 20
|
|
377
|
+
)
|
|
342
378
|
await ui.success(f"Configuration refreshed - max iterations: {max_iterations}")
|
|
343
379
|
|
|
344
380
|
|
|
@@ -507,23 +543,20 @@ class UpdateCommand(SimpleCommand):
|
|
|
507
543
|
)
|
|
508
544
|
|
|
509
545
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
546
|
+
import shutil
|
|
510
547
|
import subprocess
|
|
511
548
|
import sys
|
|
512
|
-
import shutil
|
|
513
549
|
|
|
514
550
|
await ui.info("Checking for TunaCode updates...")
|
|
515
551
|
|
|
516
552
|
# Detect installation method
|
|
517
553
|
installation_method = None
|
|
518
|
-
|
|
554
|
+
|
|
519
555
|
# Check if installed via pipx
|
|
520
556
|
if shutil.which("pipx"):
|
|
521
557
|
try:
|
|
522
558
|
result = subprocess.run(
|
|
523
|
-
["pipx", "list"],
|
|
524
|
-
capture_output=True,
|
|
525
|
-
text=True,
|
|
526
|
-
timeout=10
|
|
559
|
+
["pipx", "list"], capture_output=True, text=True, timeout=10
|
|
527
560
|
)
|
|
528
561
|
if "tunacode" in result.stdout.lower():
|
|
529
562
|
installation_method = "pipx"
|
|
@@ -534,10 +567,10 @@ class UpdateCommand(SimpleCommand):
|
|
|
534
567
|
if not installation_method:
|
|
535
568
|
try:
|
|
536
569
|
result = subprocess.run(
|
|
537
|
-
[sys.executable, "-m", "pip", "show", "tunacode-cli"],
|
|
538
|
-
capture_output=True,
|
|
539
|
-
text=True,
|
|
540
|
-
timeout=10
|
|
570
|
+
[sys.executable, "-m", "pip", "show", "tunacode-cli"],
|
|
571
|
+
capture_output=True,
|
|
572
|
+
text=True,
|
|
573
|
+
timeout=10,
|
|
541
574
|
)
|
|
542
575
|
if result.returncode == 0:
|
|
543
576
|
installation_method = "pip"
|
|
@@ -556,10 +589,7 @@ class UpdateCommand(SimpleCommand):
|
|
|
556
589
|
if installation_method == "pipx":
|
|
557
590
|
await ui.info("Updating via pipx...")
|
|
558
591
|
result = subprocess.run(
|
|
559
|
-
["pipx", "upgrade", "tunacode"],
|
|
560
|
-
capture_output=True,
|
|
561
|
-
text=True,
|
|
562
|
-
timeout=60
|
|
592
|
+
["pipx", "upgrade", "tunacode"], capture_output=True, text=True, timeout=60
|
|
563
593
|
)
|
|
564
594
|
else: # pip
|
|
565
595
|
await ui.info("Updating via pip...")
|
|
@@ -567,16 +597,16 @@ class UpdateCommand(SimpleCommand):
|
|
|
567
597
|
[sys.executable, "-m", "pip", "install", "--upgrade", "tunacode-cli"],
|
|
568
598
|
capture_output=True,
|
|
569
599
|
text=True,
|
|
570
|
-
timeout=60
|
|
600
|
+
timeout=60,
|
|
571
601
|
)
|
|
572
602
|
|
|
573
603
|
if result.returncode == 0:
|
|
574
604
|
await ui.success("TunaCode updated successfully!")
|
|
575
605
|
await ui.muted("Restart TunaCode to use the new version")
|
|
576
|
-
|
|
606
|
+
|
|
577
607
|
# Show update output if available
|
|
578
608
|
if result.stdout.strip():
|
|
579
|
-
output_lines = result.stdout.strip().split(
|
|
609
|
+
output_lines = result.stdout.strip().split("\n")
|
|
580
610
|
for line in output_lines[-5:]: # Show last 5 lines
|
|
581
611
|
if line.strip():
|
|
582
612
|
await ui.muted(f" {line}")
|
|
@@ -723,6 +753,7 @@ class CommandRegistry:
|
|
|
723
753
|
YoloCommand,
|
|
724
754
|
DumpCommand,
|
|
725
755
|
ThoughtsCommand,
|
|
756
|
+
ArchitectCommand,
|
|
726
757
|
IterationsCommand,
|
|
727
758
|
ClearCommand,
|
|
728
759
|
FixCommand,
|
|
@@ -798,8 +829,9 @@ class CommandRegistry:
|
|
|
798
829
|
return await command.execute(args, context)
|
|
799
830
|
else:
|
|
800
831
|
# Ambiguous - show possibilities
|
|
832
|
+
matches_str = ", ".join(sorted(set(matches)))
|
|
801
833
|
raise ValidationError(
|
|
802
|
-
f"Ambiguous command '{command_name}'. Did you mean: {
|
|
834
|
+
f"Ambiguous command '{command_name}'. Did you mean: {matches_str}?"
|
|
803
835
|
)
|
|
804
836
|
|
|
805
837
|
def find_matching_commands(self, partial_command: str) -> List[str]:
|
|
@@ -24,36 +24,39 @@ state_manager = StateManager()
|
|
|
24
24
|
def main(
|
|
25
25
|
version: bool = typer.Option(False, "--version", "-v", help="Show version and exit."),
|
|
26
26
|
run_setup: bool = typer.Option(False, "--setup", help="Run setup process."),
|
|
27
|
-
baseurl: str = typer.Option(
|
|
27
|
+
baseurl: str = typer.Option(
|
|
28
|
+
None, "--baseurl", help="API base URL (e.g., https://openrouter.ai/api/v1)"
|
|
29
|
+
),
|
|
28
30
|
model: str = typer.Option(None, "--model", help="Default model to use (e.g., openai/gpt-4)"),
|
|
29
31
|
key: str = typer.Option(None, "--key", help="API key for the provider"),
|
|
30
32
|
):
|
|
31
33
|
"""🚀 Start TunaCode - Your AI-powered development assistant"""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
asyncio.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
34
|
+
|
|
35
|
+
async def async_main():
|
|
36
|
+
if version:
|
|
37
|
+
await ui.version()
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
await ui.banner()
|
|
41
|
+
|
|
42
|
+
# Start update check in background
|
|
43
|
+
update_task = asyncio.to_thread(check_for_updates)
|
|
44
|
+
|
|
45
|
+
cli_config = {}
|
|
46
|
+
if baseurl or model or key:
|
|
47
|
+
cli_config = {"baseurl": baseurl, "model": model, "key": key}
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
await setup(run_setup, state_manager, cli_config)
|
|
51
|
+
await repl(state_manager)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
await ui.error(str(e))
|
|
54
|
+
|
|
55
|
+
has_update, latest_version = await update_task
|
|
56
|
+
if has_update:
|
|
57
|
+
await ui.update_available(latest_version)
|
|
58
|
+
|
|
59
|
+
asyncio.run(async_main())
|
|
57
60
|
|
|
58
61
|
|
|
59
62
|
if __name__ == "__main__":
|