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.

Files changed (81) hide show
  1. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/PKG-INFO +91 -5
  2. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/README.md +89 -3
  3. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/pyproject.toml +2 -2
  4. tunacode_cli-0.0.8/src/tunacode/cli/main.py +82 -0
  5. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/constants.py +1 -1
  6. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/tinyagent_main.py +31 -8
  7. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/config_setup.py +61 -53
  8. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/tinyagent_tools.py +1 -1
  9. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/input.py +3 -0
  10. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/prompt_manager.py +2 -0
  11. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/system.py +40 -0
  12. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/PKG-INFO +91 -5
  13. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/SOURCES.txt +2 -1
  14. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/requires.txt +1 -1
  15. tunacode_cli-0.0.8/tests/test_import.py +7 -0
  16. tunacode_cli-0.0.6/src/tunacode/cli/main.py +0 -47
  17. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/LICENSE +0 -0
  18. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/setup.cfg +0 -0
  19. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/setup.py +0 -0
  20. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/__init__.py +0 -0
  21. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/__init__.py +0 -0
  22. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/commands.py +0 -0
  23. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/model_selector.py +0 -0
  24. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/cli/repl.py +0 -0
  25. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/__init__.py +0 -0
  26. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/defaults.py +0 -0
  27. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/models.py +0 -0
  28. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/configuration/settings.py +0 -0
  29. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/context.py +0 -0
  30. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/__init__.py +0 -0
  31. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/__init__.py +0 -0
  32. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/agents/main.py +0 -0
  33. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/__init__.py +0 -0
  34. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/agent_setup.py +0 -0
  35. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/base.py +0 -0
  36. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/coordinator.py +0 -0
  37. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/environment_setup.py +0 -0
  38. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/git_safety_setup.py +0 -0
  39. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/optimized_coordinator.py +0 -0
  40. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/setup/undo_setup.py +0 -0
  41. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/state.py +0 -0
  42. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/core/tool_handler.py +0 -0
  43. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/exceptions.py +0 -0
  44. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/prompts/system.txt +0 -0
  45. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/py.typed +0 -0
  46. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/__init__.py +0 -0
  47. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/enhanced_undo_service.py +0 -0
  48. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/mcp.py +0 -0
  49. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/project_undo_service.py +0 -0
  50. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/services/undo_service.py +0 -0
  51. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/setup.py +0 -0
  52. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/__init__.py +0 -0
  53. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/base.py +0 -0
  54. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/read_file.py +0 -0
  55. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/run_command.py +0 -0
  56. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/update_file.py +0 -0
  57. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/tools/write_file.py +0 -0
  58. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/types.py +0 -0
  59. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/__init__.py +0 -0
  60. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/completers.py +0 -0
  61. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/console.py +0 -0
  62. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/constants.py +0 -0
  63. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/decorators.py +0 -0
  64. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/keybindings.py +0 -0
  65. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/lexers.py +0 -0
  66. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/output.py +0 -0
  67. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/panels.py +0 -0
  68. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/tool_ui.py +0 -0
  69. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/ui/validators.py +0 -0
  70. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/__init__.py +0 -0
  71. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/bm25.py +0 -0
  72. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/diff_utils.py +0 -0
  73. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/file_utils.py +0 -0
  74. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/lazy_imports.py +0 -0
  75. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/regex_cache.py +0 -0
  76. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/ripgrep.py +0 -0
  77. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/text_utils.py +0 -0
  78. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode/utils/user_configuration.py +0 -0
  79. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
  80. {tunacode_cli-0.0.6 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
  81. {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.6
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.15.3
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
- # Then run with OpenRouter base URL:
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
- # Then run with OpenRouter base URL:
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.6"
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.15.3",
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()
@@ -7,7 +7,7 @@ Centralizes all magic strings, UI text, error messages, and application constant
7
7
 
8
8
  # Application info
9
9
  APP_NAME = "TunaCode"
10
- APP_VERSION = "0.1.0"
10
+ APP_VERSION = "0.0.8"
11
11
 
12
12
  # File patterns
13
13
  GUIDE_FILE_PATTERN = "{name}.md"
@@ -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.react.react_agent import ReactAgent
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 the actual model name
62
- agent = ReactAgent(model_override=actual_model)
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
- result = await agent.run_react(message)
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
- "Please select a new default model.",
72
+ "Let's reconfigure your setup.",
72
73
  border_style=UI_COLORS["warning"],
73
74
  )
74
- await self._step2_default_model()
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
- await self._step1_api_keys()
118
-
119
- # Only continue if at least one API key was provided
120
- env = self.state_manager.session.user_config.get("env", {})
121
- has_api_key = any(key.endswith("_API_KEY") and env.get(key) for key in env)
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
- if has_api_key:
124
- if not self.state_manager.session.user_config.get("default_model"):
125
- await self._step2_default_model()
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
- # Compare configs to see if anything changed
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 = f"Config saved to: [bold]{self.config_file}[/bold]"
132
- await ui.panel("Finished", message, top=0, border_style=UI_COLORS["success"])
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
- "At least one API key is required.",
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)]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Optional
4
4
 
5
- from tinyagent.decorators import tool
5
+ from tinyagent import tool
6
6
 
7
7
  from tunacode.exceptions import ToolExecutionError
8
8
  from tunacode.ui import console as ui
@@ -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.6
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.15.3
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
- # Then run with OpenRouter base URL:
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
@@ -2,7 +2,7 @@ prompt_toolkit==3.0.51
2
2
  tiny_agent_os>=0.1.0
3
3
  pygments==2.19.1
4
4
  rich==14.0.0
5
- typer==0.15.3
5
+ typer==0.12.5
6
6
  pyyaml>=6.0
7
7
 
8
8
  [dev]
@@ -0,0 +1,7 @@
1
+ import os
2
+ import sys
3
+
4
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
5
+
6
+ def test_import_constants():
7
+ import tunacode.constants
@@ -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