tunacode-cli 0.0.6__tar.gz → 0.0.8__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.6 → tunacode_cli-0.0.8}/PKG-INFO +91 -5
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/README.md +89 -3
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/pyproject.toml +2 -2
- tunacode_cli-0.0.8/src/tunacode/cli/main.py +82 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/constants.py +1 -1
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/tinyagent_main.py +31 -8
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/config_setup.py +61 -53
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/tinyagent_tools.py +1 -1
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/input.py +3 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/prompt_manager.py +2 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/system.py +40 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/PKG-INFO +91 -5
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/SOURCES.txt +2 -1
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/requires.txt +1 -1
- tunacode_cli-0.0.8/tests/test_import.py +7 -0
- tunacode_cli-0.0.6/src/tunacode/cli/main.py +0 -47
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/LICENSE +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/setup.cfg +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/commands.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/model_selector.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/repl.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/defaults.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/models.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/settings.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/context.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/main.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/agent_setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/base.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/coordinator.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/environment_setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/git_safety_setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/optimized_coordinator.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/undo_setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/state.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/tool_handler.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/exceptions.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/prompts/system.txt +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/py.typed +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/enhanced_undo_service.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/mcp.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/project_undo_service.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/undo_service.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/setup.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/base.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/read_file.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/run_command.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/update_file.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/write_file.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/types.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/completers.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/console.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/constants.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/decorators.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/keybindings.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/lexers.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/output.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/panels.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/tool_ui.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/validators.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/__init__.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/bm25.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/diff_utils.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/file_utils.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/lazy_imports.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/regex_cache.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/ripgrep.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/text_utils.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/user_configuration.py +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
- {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/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.8
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: prompt_toolkit==3.0.51
|
|
|
23
23
|
Requires-Dist: tiny_agent_os>=0.1.0
|
|
24
24
|
Requires-Dist: pygments==2.19.1
|
|
25
25
|
Requires-Dist: rich==14.0.0
|
|
26
|
-
Requires-Dist: typer==0.
|
|
26
|
+
Requires-Dist: typer==0.12.5
|
|
27
27
|
Requires-Dist: pyyaml>=6.0
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: build; extra == "dev"
|
|
@@ -71,16 +71,48 @@ Dynamic: license-file
|
|
|
71
71
|
|
|
72
72
|
## 🚀 Quick Start
|
|
73
73
|
|
|
74
|
+
### One-Line Install (Linux/macOS)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Using curl
|
|
78
|
+
curl -sSL https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
79
|
+
|
|
80
|
+
# Or using wget
|
|
81
|
+
wget -qO- https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This creates a virtual environment in `~/.tunacode-venv` and adds the `tunacode` command to your PATH.
|
|
85
|
+
|
|
86
|
+
### Alternative Install Methods
|
|
87
|
+
|
|
74
88
|
```bash
|
|
75
89
|
# Install from PyPI
|
|
76
90
|
pip install tunacode-cli
|
|
77
91
|
|
|
92
|
+
# Or install globally using pipx (recommended)
|
|
93
|
+
python3 -m pip install --user pipx
|
|
94
|
+
python3 -m pipx ensurepath
|
|
95
|
+
pipx install tunacode-cli
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Start Using TunaCode
|
|
99
|
+
|
|
100
|
+
```bash
|
|
78
101
|
# Run setup (first time only)
|
|
79
102
|
tunacode
|
|
80
103
|
|
|
81
104
|
# Start coding!
|
|
82
105
|
tunacode
|
|
83
106
|
> Help me refactor this codebase to use async/await
|
|
107
|
+
|
|
108
|
+
# Update to latest version
|
|
109
|
+
tunacode --update
|
|
110
|
+
|
|
111
|
+
# Start with a specific model
|
|
112
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
113
|
+
|
|
114
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
115
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
84
116
|
```
|
|
85
117
|
|
|
86
118
|
## 📋 Commands
|
|
@@ -94,6 +126,7 @@ tunacode
|
|
|
94
126
|
| `/branch <name>` | Create new git branch | `/branch feature/auth` |
|
|
95
127
|
| `/compact` | Summarize and trim history | `/compact` |
|
|
96
128
|
| `/help` | Show all commands | `/help` |
|
|
129
|
+
| `--update` | Update to latest version | `tunacode --update` |
|
|
97
130
|
|
|
98
131
|
## 🔧 Configuration
|
|
99
132
|
|
|
@@ -117,19 +150,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
117
150
|
}
|
|
118
151
|
```
|
|
119
152
|
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# .env file
|
|
159
|
+
OPENAI_API_KEY=sk-...
|
|
160
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
161
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Environment variables take precedence over config file values.
|
|
165
|
+
|
|
166
|
+
### TinyAgent Configuration
|
|
167
|
+
|
|
168
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# Model and API configuration
|
|
172
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
173
|
+
model:
|
|
174
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
175
|
+
|
|
176
|
+
# File operations
|
|
177
|
+
file_operations:
|
|
178
|
+
max_file_size: 10_485_760 # 10 MB
|
|
179
|
+
allow_overwrite: true
|
|
180
|
+
|
|
181
|
+
# Retry configuration
|
|
182
|
+
retries:
|
|
183
|
+
max_attempts: 3
|
|
184
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
188
|
+
|
|
120
189
|
### Using OpenRouter (100+ Models)
|
|
121
190
|
|
|
122
191
|
```bash
|
|
123
|
-
# Add your OpenRouter API key to config
|
|
124
|
-
#
|
|
125
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
192
|
+
# Add your OpenRouter API key to config or .env file
|
|
193
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
126
194
|
|
|
127
195
|
# Use any OpenRouter model:
|
|
196
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
197
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
198
|
+
|
|
199
|
+
# Or switch models inside TunaCode:
|
|
128
200
|
/model openrouter:anthropic/claude-3-opus
|
|
129
201
|
/model openrouter:mistralai/devstral-small
|
|
130
202
|
/model openrouter:openai/gpt-4.1
|
|
131
203
|
```
|
|
132
204
|
|
|
205
|
+
### OpenAI-Compatible APIs
|
|
206
|
+
|
|
207
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Use a local LLM server
|
|
211
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
212
|
+
|
|
213
|
+
# Use alternative OpenAI-compatible services
|
|
214
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
218
|
+
|
|
133
219
|
## 🛡️ Undo System
|
|
134
220
|
|
|
135
221
|
TunaCode provides **three layers of protection** for your files:
|
|
@@ -35,16 +35,48 @@
|
|
|
35
35
|
|
|
36
36
|
## 🚀 Quick Start
|
|
37
37
|
|
|
38
|
+
### One-Line Install (Linux/macOS)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Using curl
|
|
42
|
+
curl -sSL https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
43
|
+
|
|
44
|
+
# Or using wget
|
|
45
|
+
wget -qO- https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This creates a virtual environment in `~/.tunacode-venv` and adds the `tunacode` command to your PATH.
|
|
49
|
+
|
|
50
|
+
### Alternative Install Methods
|
|
51
|
+
|
|
38
52
|
```bash
|
|
39
53
|
# Install from PyPI
|
|
40
54
|
pip install tunacode-cli
|
|
41
55
|
|
|
56
|
+
# Or install globally using pipx (recommended)
|
|
57
|
+
python3 -m pip install --user pipx
|
|
58
|
+
python3 -m pipx ensurepath
|
|
59
|
+
pipx install tunacode-cli
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Start Using TunaCode
|
|
63
|
+
|
|
64
|
+
```bash
|
|
42
65
|
# Run setup (first time only)
|
|
43
66
|
tunacode
|
|
44
67
|
|
|
45
68
|
# Start coding!
|
|
46
69
|
tunacode
|
|
47
70
|
> Help me refactor this codebase to use async/await
|
|
71
|
+
|
|
72
|
+
# Update to latest version
|
|
73
|
+
tunacode --update
|
|
74
|
+
|
|
75
|
+
# Start with a specific model
|
|
76
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
77
|
+
|
|
78
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
79
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
48
80
|
```
|
|
49
81
|
|
|
50
82
|
## 📋 Commands
|
|
@@ -58,6 +90,7 @@ tunacode
|
|
|
58
90
|
| `/branch <name>` | Create new git branch | `/branch feature/auth` |
|
|
59
91
|
| `/compact` | Summarize and trim history | `/compact` |
|
|
60
92
|
| `/help` | Show all commands | `/help` |
|
|
93
|
+
| `--update` | Update to latest version | `tunacode --update` |
|
|
61
94
|
|
|
62
95
|
## 🔧 Configuration
|
|
63
96
|
|
|
@@ -81,19 +114,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
81
114
|
}
|
|
82
115
|
```
|
|
83
116
|
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# .env file
|
|
123
|
+
OPENAI_API_KEY=sk-...
|
|
124
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
125
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Environment variables take precedence over config file values.
|
|
129
|
+
|
|
130
|
+
### TinyAgent Configuration
|
|
131
|
+
|
|
132
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# Model and API configuration
|
|
136
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
137
|
+
model:
|
|
138
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
139
|
+
|
|
140
|
+
# File operations
|
|
141
|
+
file_operations:
|
|
142
|
+
max_file_size: 10_485_760 # 10 MB
|
|
143
|
+
allow_overwrite: true
|
|
144
|
+
|
|
145
|
+
# Retry configuration
|
|
146
|
+
retries:
|
|
147
|
+
max_attempts: 3
|
|
148
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
152
|
+
|
|
84
153
|
### Using OpenRouter (100+ Models)
|
|
85
154
|
|
|
86
155
|
```bash
|
|
87
|
-
# Add your OpenRouter API key to config
|
|
88
|
-
#
|
|
89
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
156
|
+
# Add your OpenRouter API key to config or .env file
|
|
157
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
90
158
|
|
|
91
159
|
# Use any OpenRouter model:
|
|
160
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
161
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
162
|
+
|
|
163
|
+
# Or switch models inside TunaCode:
|
|
92
164
|
/model openrouter:anthropic/claude-3-opus
|
|
93
165
|
/model openrouter:mistralai/devstral-small
|
|
94
166
|
/model openrouter:openai/gpt-4.1
|
|
95
167
|
```
|
|
96
168
|
|
|
169
|
+
### OpenAI-Compatible APIs
|
|
170
|
+
|
|
171
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Use a local LLM server
|
|
175
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
176
|
+
|
|
177
|
+
# Use alternative OpenAI-compatible services
|
|
178
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
182
|
+
|
|
97
183
|
## 🛡️ Undo System
|
|
98
184
|
|
|
99
185
|
TunaCode provides **three layers of protection** for your files:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tunacode-cli"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.8"
|
|
8
8
|
description = "Your agentic CLI developer."
|
|
9
9
|
keywords = ["cli", "agent", "development", "automation"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -29,7 +29,7 @@ dependencies = [
|
|
|
29
29
|
"tiny_agent_os>=0.1.0",
|
|
30
30
|
"pygments==2.19.1",
|
|
31
31
|
"rich==14.0.0",
|
|
32
|
-
"typer==0.
|
|
32
|
+
"typer==0.12.5",
|
|
33
33
|
"pyyaml>=6.0",
|
|
34
34
|
]
|
|
35
35
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module: sidekick.cli.main
|
|
3
|
+
|
|
4
|
+
CLI entry point and main command handling for the Sidekick application.
|
|
5
|
+
Manages application startup, version checking, and REPL initialization.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
from tunacode.cli.repl import repl
|
|
15
|
+
from tunacode.configuration.settings import ApplicationSettings
|
|
16
|
+
from tunacode.core.state import StateManager
|
|
17
|
+
from tunacode.setup import setup
|
|
18
|
+
from tunacode.ui import console as ui
|
|
19
|
+
from tunacode.utils.system import check_for_updates
|
|
20
|
+
|
|
21
|
+
app_settings = ApplicationSettings()
|
|
22
|
+
state_manager = StateManager()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main(
|
|
26
|
+
version: bool = typer.Option(False, "--version", "-v", help="Show version and exit."),
|
|
27
|
+
run_setup: bool = typer.Option(False, "--setup", help="Run setup process."),
|
|
28
|
+
update: bool = typer.Option(False, "--update", "--upgrade", help="Update TunaCode to the latest version."),
|
|
29
|
+
model: str = typer.Option(None, "--model", "-m", help="Set the model to use (e.g., 'openai:gpt-4o', 'openrouter:anthropic/claude-3.5-sonnet')."),
|
|
30
|
+
base_url: str = typer.Option(None, "--base-url", help="Override the API base URL for OpenAI-compatible endpoints (e.g., 'https://openrouter.ai/api/v1')."),
|
|
31
|
+
):
|
|
32
|
+
"""TunaCode - Your agentic CLI developer."""
|
|
33
|
+
# Load .env file if it exists
|
|
34
|
+
env_file = Path(".env")
|
|
35
|
+
if env_file.exists():
|
|
36
|
+
try:
|
|
37
|
+
from dotenv import load_dotenv
|
|
38
|
+
load_dotenv()
|
|
39
|
+
except ImportError:
|
|
40
|
+
# dotenv not installed, skip loading
|
|
41
|
+
pass
|
|
42
|
+
if version:
|
|
43
|
+
asyncio.run(ui.version())
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
if update:
|
|
47
|
+
from tunacode.utils.system import update_tunacode
|
|
48
|
+
asyncio.run(update_tunacode())
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# Apply CLI overrides to state manager before setup
|
|
52
|
+
if model:
|
|
53
|
+
state_manager.session.model = model
|
|
54
|
+
state_manager.session.user_config["default_model"] = model
|
|
55
|
+
|
|
56
|
+
if base_url:
|
|
57
|
+
import os
|
|
58
|
+
os.environ["OPENAI_BASE_URL"] = base_url
|
|
59
|
+
|
|
60
|
+
asyncio.run(ui.banner())
|
|
61
|
+
|
|
62
|
+
has_update, latest_version = check_for_updates()
|
|
63
|
+
if has_update:
|
|
64
|
+
asyncio.run(ui.show_update_message(latest_version))
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
asyncio.run(setup(run_setup, state_manager))
|
|
68
|
+
asyncio.run(repl(state_manager))
|
|
69
|
+
except Exception as e:
|
|
70
|
+
asyncio.run(ui.error(str(e)))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
app = typer.Typer(
|
|
74
|
+
name="tunacode",
|
|
75
|
+
help="TunaCode - Your agentic CLI developer",
|
|
76
|
+
add_completion=False,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
app.command()(main)
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
app()
|
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
"""TinyAgent-based agent implementation."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from contextlib import asynccontextmanager
|
|
4
5
|
from datetime import datetime, timezone
|
|
6
|
+
from pathlib import Path
|
|
5
7
|
from typing import Any, Dict, Optional
|
|
6
8
|
|
|
7
|
-
from tinyagent
|
|
9
|
+
from tinyagent import ReactAgent
|
|
8
10
|
|
|
9
11
|
from tunacode.core.state import StateManager
|
|
10
12
|
from tunacode.tools.tinyagent_tools import read_file, run_command, update_file, write_file
|
|
11
13
|
from tunacode.types import ModelName, ToolCallback
|
|
12
14
|
|
|
15
|
+
# Set up tinyagent configuration
|
|
16
|
+
# First check if config exists in the package directory
|
|
17
|
+
_package_dir = Path(__file__).parent.parent.parent.parent # Navigate to tunacode root
|
|
18
|
+
_config_candidates = [
|
|
19
|
+
_package_dir / "tunacode_config.yml", # In package root
|
|
20
|
+
Path.home() / ".config" / "tunacode_config.yml", # In user config dir
|
|
21
|
+
Path.cwd() / "tunacode_config.yml", # In current directory
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# Find the first existing config file
|
|
25
|
+
for config_path in _config_candidates:
|
|
26
|
+
if config_path.exists():
|
|
27
|
+
os.environ["TINYAGENT_CONFIG"] = str(config_path)
|
|
28
|
+
break
|
|
29
|
+
else:
|
|
30
|
+
# If no config found, we'll rely on tinyagent to handle it
|
|
31
|
+
# This prevents the immediate error on import
|
|
32
|
+
pass
|
|
33
|
+
|
|
13
34
|
|
|
14
35
|
def get_or_create_react_agent(model: ModelName, state_manager: StateManager) -> ReactAgent:
|
|
15
36
|
"""
|
|
@@ -58,12 +79,9 @@ def get_or_create_react_agent(model: ModelName, state_manager: StateManager) ->
|
|
|
58
79
|
if state_manager.session.user_config["env"].get(key_name):
|
|
59
80
|
os.environ[key_name] = state_manager.session.user_config["env"][key_name]
|
|
60
81
|
|
|
61
|
-
# Create new ReactAgent with
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
# Register our tools
|
|
65
|
-
for fn in (read_file, write_file, update_file, run_command):
|
|
66
|
-
agent.register_tool(fn._tool)
|
|
82
|
+
# Create new ReactAgent with tools
|
|
83
|
+
# Note: tinyAgent gets model from environment variables, not constructor
|
|
84
|
+
agent = ReactAgent(tools=[read_file, write_file, update_file, run_command])
|
|
67
85
|
|
|
68
86
|
# Add MCP compatibility method
|
|
69
87
|
@asynccontextmanager
|
|
@@ -106,7 +124,12 @@ async def process_request_with_tinyagent(
|
|
|
106
124
|
|
|
107
125
|
try:
|
|
108
126
|
# Run the agent with the message
|
|
109
|
-
|
|
127
|
+
# The new API's run() method might be synchronous based on the examples
|
|
128
|
+
import asyncio
|
|
129
|
+
if asyncio.iscoroutinefunction(agent.run):
|
|
130
|
+
result = await agent.run(message)
|
|
131
|
+
else:
|
|
132
|
+
result = agent.run(message)
|
|
110
133
|
|
|
111
134
|
# Update message history in state_manager
|
|
112
135
|
# This will need to be adapted based on how tinyAgent returns messages
|
|
@@ -65,14 +65,14 @@ class ConfigSetup(BaseSetup):
|
|
|
65
65
|
# Check if the configured model still exists
|
|
66
66
|
default_model = self.state_manager.session.user_config["default_model"]
|
|
67
67
|
if not self.model_registry.get_model(default_model):
|
|
68
|
+
# If model not found, run the onboarding again
|
|
68
69
|
await ui.panel(
|
|
69
70
|
"Model Not Found",
|
|
70
71
|
f"The configured model '[bold]{default_model}[/bold]' is no longer available.\n"
|
|
71
|
-
"
|
|
72
|
+
"Let's reconfigure your setup.",
|
|
72
73
|
border_style=UI_COLORS["warning"],
|
|
73
74
|
)
|
|
74
|
-
await self.
|
|
75
|
-
user_configuration.save_config(self.state_manager)
|
|
75
|
+
await self._onboarding()
|
|
76
76
|
|
|
77
77
|
self.state_manager.session.current_model = self.state_manager.session.user_config[
|
|
78
78
|
"default_model"
|
|
@@ -114,66 +114,74 @@ class ConfigSetup(BaseSetup):
|
|
|
114
114
|
"""Run the onboarding process for new users."""
|
|
115
115
|
initial_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
# Welcome message
|
|
118
|
+
message = (
|
|
119
|
+
f"Welcome to {APP_NAME}!\n\n"
|
|
120
|
+
"Let's configure your AI provider. TunaCode supports:\n"
|
|
121
|
+
"• OpenAI (api.openai.com)\n"
|
|
122
|
+
"• OpenRouter (openrouter.ai) - Access 100+ models\n"
|
|
123
|
+
"• Any OpenAI-compatible API\n"
|
|
124
|
+
)
|
|
125
|
+
await ui.panel("Setup", message, border_style=UI_COLORS["primary"])
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
# Step 1: Ask for base URL
|
|
128
|
+
base_url = await ui.input(
|
|
129
|
+
"step1",
|
|
130
|
+
pretext=" API Base URL (press Enter for OpenAI): ",
|
|
131
|
+
default="https://api.openai.com/v1",
|
|
132
|
+
state_manager=self.state_manager,
|
|
133
|
+
)
|
|
134
|
+
base_url = base_url.strip()
|
|
135
|
+
if not base_url:
|
|
136
|
+
base_url = "https://api.openai.com/v1"
|
|
137
|
+
|
|
138
|
+
# Step 2: Ask for API key
|
|
139
|
+
if "openrouter.ai" in base_url.lower():
|
|
140
|
+
key_prompt = " OpenRouter API Key: "
|
|
141
|
+
key_name = "OPENROUTER_API_KEY"
|
|
142
|
+
default_model = "openrouter:openai/gpt-4o-mini"
|
|
143
|
+
else:
|
|
144
|
+
key_prompt = " API Key: "
|
|
145
|
+
key_name = "OPENAI_API_KEY"
|
|
146
|
+
default_model = "openai:gpt-4o"
|
|
126
147
|
|
|
127
|
-
|
|
148
|
+
api_key = await ui.input(
|
|
149
|
+
"step2",
|
|
150
|
+
pretext=key_prompt,
|
|
151
|
+
is_password=True,
|
|
152
|
+
state_manager=self.state_manager,
|
|
153
|
+
)
|
|
154
|
+
api_key = api_key.strip()
|
|
155
|
+
|
|
156
|
+
if api_key:
|
|
157
|
+
# Set the environment variable
|
|
158
|
+
self.state_manager.session.user_config["env"][key_name] = api_key
|
|
159
|
+
|
|
160
|
+
# Set base URL in environment for OpenRouter
|
|
161
|
+
if "openrouter.ai" in base_url.lower():
|
|
162
|
+
import os
|
|
163
|
+
os.environ["OPENAI_BASE_URL"] = base_url
|
|
164
|
+
|
|
165
|
+
# Set default model
|
|
166
|
+
self.state_manager.session.user_config["default_model"] = default_model
|
|
167
|
+
|
|
168
|
+
# Save configuration
|
|
128
169
|
current_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
|
|
129
170
|
if initial_config != current_config:
|
|
130
171
|
if user_configuration.save_config(self.state_manager):
|
|
131
|
-
message =
|
|
132
|
-
|
|
172
|
+
message = (
|
|
173
|
+
f"✅ Configuration saved!\n\n"
|
|
174
|
+
f"Default model: {default_model}\n"
|
|
175
|
+
f"Config file: {self.config_file}\n\n"
|
|
176
|
+
f"You can change models anytime with /model"
|
|
177
|
+
)
|
|
178
|
+
await ui.panel("Setup Complete", message, top=0, border_style=UI_COLORS["success"])
|
|
133
179
|
else:
|
|
134
180
|
await ui.error("Failed to save configuration.")
|
|
135
181
|
else:
|
|
136
182
|
await ui.panel(
|
|
137
183
|
"Setup canceled",
|
|
138
|
-
"
|
|
184
|
+
"An API key is required to use TunaCode.",
|
|
139
185
|
border_style=UI_COLORS["warning"],
|
|
140
186
|
)
|
|
141
187
|
|
|
142
|
-
async def _step1_api_keys(self):
|
|
143
|
-
"""Onboarding step 1: Collect API keys."""
|
|
144
|
-
message = (
|
|
145
|
-
f"Welcome to {APP_NAME}!\n"
|
|
146
|
-
"Let's get you setup. First, we'll need to set some environment variables.\n"
|
|
147
|
-
"Skip the ones you don't need."
|
|
148
|
-
)
|
|
149
|
-
await ui.panel("Setup", message, border_style=UI_COLORS["primary"])
|
|
150
|
-
env_keys = self.state_manager.session.user_config["env"].copy()
|
|
151
|
-
for key in env_keys:
|
|
152
|
-
provider = key_to_title(key)
|
|
153
|
-
val = await ui.input(
|
|
154
|
-
"step1",
|
|
155
|
-
pretext=f" {provider}: ",
|
|
156
|
-
is_password=True,
|
|
157
|
-
state_manager=self.state_manager,
|
|
158
|
-
)
|
|
159
|
-
val = val.strip()
|
|
160
|
-
if val:
|
|
161
|
-
self.state_manager.session.user_config["env"][key] = val
|
|
162
|
-
|
|
163
|
-
async def _step2_default_model(self):
|
|
164
|
-
"""Onboarding step 2: Select default model."""
|
|
165
|
-
message = "Which model would you like to use by default?\n\n"
|
|
166
|
-
|
|
167
|
-
model_ids = self.model_registry.list_model_ids()
|
|
168
|
-
for index, model_id in enumerate(model_ids):
|
|
169
|
-
message += f" {index} - {model_id}\n"
|
|
170
|
-
message = message.strip()
|
|
171
|
-
|
|
172
|
-
await ui.panel("Default Model", message, border_style=UI_COLORS["primary"])
|
|
173
|
-
choice = await ui.input(
|
|
174
|
-
"step2",
|
|
175
|
-
pretext=" Default model (#): ",
|
|
176
|
-
validator=ui.ModelValidator(len(model_ids)),
|
|
177
|
-
state_manager=self.state_manager,
|
|
178
|
-
)
|
|
179
|
-
self.state_manager.session.user_config["default_model"] = model_ids[int(choice)]
|
|
@@ -32,6 +32,7 @@ async def input(
|
|
|
32
32
|
lexer=None,
|
|
33
33
|
timeoutlen: float = 0.05,
|
|
34
34
|
state_manager: Optional[StateManager] = None,
|
|
35
|
+
default: str = "",
|
|
35
36
|
) -> str:
|
|
36
37
|
"""
|
|
37
38
|
Prompt for user input using simplified prompt management.
|
|
@@ -48,6 +49,7 @@ async def input(
|
|
|
48
49
|
lexer: Optional lexer for syntax highlighting
|
|
49
50
|
timeoutlen: Timeout length for input
|
|
50
51
|
state_manager: The state manager for session storage
|
|
52
|
+
default: Default value to pre-fill in the input
|
|
51
53
|
|
|
52
54
|
Returns:
|
|
53
55
|
User input string
|
|
@@ -62,6 +64,7 @@ async def input(
|
|
|
62
64
|
completer=completer,
|
|
63
65
|
lexer=lexer,
|
|
64
66
|
timeoutlen=timeoutlen,
|
|
67
|
+
default=default,
|
|
65
68
|
)
|
|
66
69
|
|
|
67
70
|
# Create prompt manager
|
|
@@ -28,6 +28,7 @@ class PromptConfig:
|
|
|
28
28
|
completer: Optional[Completer] = None
|
|
29
29
|
lexer: Optional[Lexer] = None
|
|
30
30
|
timeoutlen: float = 0.05
|
|
31
|
+
default: str = ""
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class PromptManager:
|
|
@@ -107,6 +108,7 @@ class PromptManager:
|
|
|
107
108
|
is_password=config.is_password,
|
|
108
109
|
validator=config.validator,
|
|
109
110
|
multiline=config.multiline,
|
|
111
|
+
default=config.default,
|
|
110
112
|
)
|
|
111
113
|
|
|
112
114
|
# Clean up response
|
|
@@ -277,6 +277,46 @@ def check_for_updates():
|
|
|
277
277
|
return False, current_version
|
|
278
278
|
|
|
279
279
|
|
|
280
|
+
async def update_tunacode():
|
|
281
|
+
"""
|
|
282
|
+
Update TunaCode to the latest version using pip.
|
|
283
|
+
"""
|
|
284
|
+
from ..ui import console as ui
|
|
285
|
+
|
|
286
|
+
await ui.info("🔄 Checking for updates...")
|
|
287
|
+
|
|
288
|
+
has_update, latest_version = check_for_updates()
|
|
289
|
+
|
|
290
|
+
if not has_update:
|
|
291
|
+
await ui.success("✅ TunaCode is already up to date!")
|
|
292
|
+
return
|
|
293
|
+
|
|
294
|
+
app_settings = ApplicationSettings()
|
|
295
|
+
current_version = app_settings.version
|
|
296
|
+
|
|
297
|
+
await ui.info(f"📦 Updating from v{current_version} to v{latest_version}...")
|
|
298
|
+
|
|
299
|
+
try:
|
|
300
|
+
# Run pip install --upgrade tunacode-cli
|
|
301
|
+
result = subprocess.run(
|
|
302
|
+
["pip", "install", "--upgrade", "tunacode-cli"],
|
|
303
|
+
capture_output=True,
|
|
304
|
+
text=True,
|
|
305
|
+
check=True
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if result.returncode == 0:
|
|
309
|
+
await ui.success(f"🎉 Successfully updated to v{latest_version}!")
|
|
310
|
+
await ui.info("Please restart TunaCode to use the new version.")
|
|
311
|
+
else:
|
|
312
|
+
await ui.error(f"❌ Update failed: {result.stderr}")
|
|
313
|
+
|
|
314
|
+
except subprocess.CalledProcessError as e:
|
|
315
|
+
await ui.error(f"❌ Update failed: {e.stderr}")
|
|
316
|
+
except Exception as e:
|
|
317
|
+
await ui.error(f"❌ Update failed: {str(e)}")
|
|
318
|
+
|
|
319
|
+
|
|
280
320
|
def list_cwd(max_depth=3):
|
|
281
321
|
"""
|
|
282
322
|
Lists files in the current working directory up to a specified depth,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunacode-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: prompt_toolkit==3.0.51
|
|
|
23
23
|
Requires-Dist: tiny_agent_os>=0.1.0
|
|
24
24
|
Requires-Dist: pygments==2.19.1
|
|
25
25
|
Requires-Dist: rich==14.0.0
|
|
26
|
-
Requires-Dist: typer==0.
|
|
26
|
+
Requires-Dist: typer==0.12.5
|
|
27
27
|
Requires-Dist: pyyaml>=6.0
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: build; extra == "dev"
|
|
@@ -71,16 +71,48 @@ Dynamic: license-file
|
|
|
71
71
|
|
|
72
72
|
## 🚀 Quick Start
|
|
73
73
|
|
|
74
|
+
### One-Line Install (Linux/macOS)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Using curl
|
|
78
|
+
curl -sSL https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
79
|
+
|
|
80
|
+
# Or using wget
|
|
81
|
+
wget -qO- https://raw.githubusercontent.com/alchemiststudiosDOTai/tunacode/master/scripts/install_linux.sh | bash
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This creates a virtual environment in `~/.tunacode-venv` and adds the `tunacode` command to your PATH.
|
|
85
|
+
|
|
86
|
+
### Alternative Install Methods
|
|
87
|
+
|
|
74
88
|
```bash
|
|
75
89
|
# Install from PyPI
|
|
76
90
|
pip install tunacode-cli
|
|
77
91
|
|
|
92
|
+
# Or install globally using pipx (recommended)
|
|
93
|
+
python3 -m pip install --user pipx
|
|
94
|
+
python3 -m pipx ensurepath
|
|
95
|
+
pipx install tunacode-cli
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Start Using TunaCode
|
|
99
|
+
|
|
100
|
+
```bash
|
|
78
101
|
# Run setup (first time only)
|
|
79
102
|
tunacode
|
|
80
103
|
|
|
81
104
|
# Start coding!
|
|
82
105
|
tunacode
|
|
83
106
|
> Help me refactor this codebase to use async/await
|
|
107
|
+
|
|
108
|
+
# Update to latest version
|
|
109
|
+
tunacode --update
|
|
110
|
+
|
|
111
|
+
# Start with a specific model
|
|
112
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
113
|
+
|
|
114
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
115
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
84
116
|
```
|
|
85
117
|
|
|
86
118
|
## 📋 Commands
|
|
@@ -94,6 +126,7 @@ tunacode
|
|
|
94
126
|
| `/branch <name>` | Create new git branch | `/branch feature/auth` |
|
|
95
127
|
| `/compact` | Summarize and trim history | `/compact` |
|
|
96
128
|
| `/help` | Show all commands | `/help` |
|
|
129
|
+
| `--update` | Update to latest version | `tunacode --update` |
|
|
97
130
|
|
|
98
131
|
## 🔧 Configuration
|
|
99
132
|
|
|
@@ -117,19 +150,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
117
150
|
}
|
|
118
151
|
```
|
|
119
152
|
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# .env file
|
|
159
|
+
OPENAI_API_KEY=sk-...
|
|
160
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
161
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Environment variables take precedence over config file values.
|
|
165
|
+
|
|
166
|
+
### TinyAgent Configuration
|
|
167
|
+
|
|
168
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# Model and API configuration
|
|
172
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
173
|
+
model:
|
|
174
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
175
|
+
|
|
176
|
+
# File operations
|
|
177
|
+
file_operations:
|
|
178
|
+
max_file_size: 10_485_760 # 10 MB
|
|
179
|
+
allow_overwrite: true
|
|
180
|
+
|
|
181
|
+
# Retry configuration
|
|
182
|
+
retries:
|
|
183
|
+
max_attempts: 3
|
|
184
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
188
|
+
|
|
120
189
|
### Using OpenRouter (100+ Models)
|
|
121
190
|
|
|
122
191
|
```bash
|
|
123
|
-
# Add your OpenRouter API key to config
|
|
124
|
-
#
|
|
125
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
192
|
+
# Add your OpenRouter API key to config or .env file
|
|
193
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
126
194
|
|
|
127
195
|
# Use any OpenRouter model:
|
|
196
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
197
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
198
|
+
|
|
199
|
+
# Or switch models inside TunaCode:
|
|
128
200
|
/model openrouter:anthropic/claude-3-opus
|
|
129
201
|
/model openrouter:mistralai/devstral-small
|
|
130
202
|
/model openrouter:openai/gpt-4.1
|
|
131
203
|
```
|
|
132
204
|
|
|
205
|
+
### OpenAI-Compatible APIs
|
|
206
|
+
|
|
207
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Use a local LLM server
|
|
211
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
212
|
+
|
|
213
|
+
# Use alternative OpenAI-compatible services
|
|
214
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
218
|
+
|
|
133
219
|
## 🛡️ Undo System
|
|
134
220
|
|
|
135
221
|
TunaCode provides **three layers of protection** for your files:
|
|
@@ -74,4 +74,5 @@ src/tunacode_cli.egg-info/SOURCES.txt
|
|
|
74
74
|
src/tunacode_cli.egg-info/dependency_links.txt
|
|
75
75
|
src/tunacode_cli.egg-info/entry_points.txt
|
|
76
76
|
src/tunacode_cli.egg-info/requires.txt
|
|
77
|
-
src/tunacode_cli.egg-info/top_level.txt
|
|
77
|
+
src/tunacode_cli.egg-info/top_level.txt
|
|
78
|
+
tests/test_import.py
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module: sidekick.cli.main
|
|
3
|
-
|
|
4
|
-
CLI entry point and main command handling for the Sidekick application.
|
|
5
|
-
Manages application startup, version checking, and REPL initialization.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import asyncio
|
|
9
|
-
|
|
10
|
-
import typer
|
|
11
|
-
|
|
12
|
-
from tunacode.cli.repl import repl
|
|
13
|
-
from tunacode.configuration.settings import ApplicationSettings
|
|
14
|
-
from tunacode.core.state import StateManager
|
|
15
|
-
from tunacode.setup import setup
|
|
16
|
-
from tunacode.ui import console as ui
|
|
17
|
-
from tunacode.utils.system import check_for_updates
|
|
18
|
-
|
|
19
|
-
app_settings = ApplicationSettings()
|
|
20
|
-
app = typer.Typer(help=app_settings.name)
|
|
21
|
-
state_manager = StateManager()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@app.command()
|
|
25
|
-
def main(
|
|
26
|
-
version: bool = typer.Option(False, "--version", "-v", help="Show version and exit."),
|
|
27
|
-
run_setup: bool = typer.Option(False, "--setup", help="Run setup process."),
|
|
28
|
-
):
|
|
29
|
-
if version:
|
|
30
|
-
asyncio.run(ui.version())
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
asyncio.run(ui.banner())
|
|
34
|
-
|
|
35
|
-
has_update, latest_version = check_for_updates()
|
|
36
|
-
if has_update:
|
|
37
|
-
asyncio.run(ui.show_update_message(latest_version))
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
asyncio.run(setup(run_setup, state_manager))
|
|
41
|
-
asyncio.run(repl(state_manager))
|
|
42
|
-
except Exception as e:
|
|
43
|
-
asyncio.run(ui.error(str(e)))
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if __name__ == "__main__":
|
|
47
|
-
app()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|