tunacode-cli 0.0.33__py3-none-any.whl → 0.0.34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tunacode-cli might be problematic. Click here for more details.

tunacode/cli/commands.py CHANGED
@@ -6,7 +6,7 @@ from enum import Enum
6
6
  from typing import Any, Dict, List, Optional, Type
7
7
 
8
8
  from .. import utils
9
- from ..exceptions import ValidationError
9
+ from ..exceptions import ConfigurationError, ValidationError
10
10
  from ..types import CommandArgs, CommandContext, CommandResult, ProcessRequestCallback
11
11
  from ..ui import console as ui
12
12
 
@@ -628,9 +628,13 @@ class ModelCommand(SimpleCommand):
628
628
 
629
629
  # Check if setting as default
630
630
  if len(args) > 1 and args[1] == "default":
631
- utils.user_configuration.set_default_model(model_name, context.state_manager)
632
- await ui.muted("Updating default model")
633
- return "restart"
631
+ try:
632
+ utils.user_configuration.set_default_model(model_name, context.state_manager)
633
+ await ui.muted("Updating default model")
634
+ return "restart"
635
+ except ConfigurationError as e:
636
+ await ui.error(str(e))
637
+ return None
634
638
 
635
639
  # Show success message with the new model
636
640
  await ui.success(f"Switched to model: {model_name}")
@@ -669,6 +673,35 @@ class CommandFactory:
669
673
  setattr(self.dependencies, key, value)
670
674
 
671
675
 
676
+ class InitCommand(SimpleCommand):
677
+ """Creates or updates TUNACODE.md with project-specific context."""
678
+
679
+ spec = CommandSpec(
680
+ name="/init",
681
+ aliases=[],
682
+ description="Analyze codebase and create/update TUNACODE.md file",
683
+ category=CommandCategory.DEVELOPMENT,
684
+ )
685
+
686
+ async def execute(self, args, context: CommandContext) -> CommandResult:
687
+ """Execute the init command."""
688
+ # Minimal implementation to make test pass
689
+ prompt = """Please analyze this codebase and create a TUNACODE.md file containing:
690
+ 1. Build/lint/test commands - especially for running a single test
691
+ 2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
692
+
693
+ The file you create will be given to agentic coding agents (such as yourself) that operate in this repository.
694
+ Make it about 20 lines long.
695
+ If there's already a TUNACODE.md, improve it.
696
+ If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md),
697
+ make sure to include them."""
698
+
699
+ # Call the agent to analyze and create/update the file
700
+ await context.process_request(prompt, context.state_manager)
701
+
702
+ return None
703
+
704
+
672
705
  class CommandRegistry:
673
706
  """Registry for managing commands with auto-discovery and categories."""
674
707
 
@@ -726,6 +759,7 @@ class CommandRegistry:
726
759
  BranchCommand,
727
760
  CompactCommand,
728
761
  ModelCommand,
762
+ InitCommand,
729
763
  ]
730
764
 
731
765
  # Register all discovered commands
tunacode/constants.py CHANGED
@@ -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.0.33"
10
+ APP_VERSION = "0.0.34"
11
11
 
12
12
  # File patterns
13
13
  GUIDE_FILE_PATTERN = "{name}.md"
@@ -457,6 +457,26 @@ def get_or_create_agent(model: ModelName, state_manager: StateManager) -> Pydant
457
457
  # Use a default system prompt if neither file exists
458
458
  system_prompt = "You are a helpful AI assistant for software development tasks."
459
459
 
460
+ # Load TUNACODE.md context
461
+ # Use sync version of get_code_style to avoid nested event loop issues
462
+ try:
463
+ from pathlib import Path as PathlibPath
464
+
465
+ tunacode_path = PathlibPath.cwd() / "TUNACODE.md"
466
+ if tunacode_path.exists():
467
+ tunacode_content = tunacode_path.read_text(encoding="utf-8")
468
+ if tunacode_content.strip():
469
+ # Log that we found TUNACODE.md
470
+ print("📄 TUNACODE.md located: Loading context...")
471
+
472
+ system_prompt += "\n\n# Project Context from TUNACODE.md\n" + tunacode_content
473
+ else:
474
+ # Log that TUNACODE.md was not found
475
+ print("📄 TUNACODE.md not found: Using default context")
476
+ except Exception:
477
+ # Ignore errors loading TUNACODE.md
478
+ pass
479
+
460
480
  state_manager.session.agents[model] = Agent(
461
481
  model=model,
462
482
  system_prompt=system_prompt,
@@ -670,6 +690,14 @@ async def process_request(
670
690
  # Create a request-level buffer for batching read-only tools across nodes
671
691
  tool_buffer = ToolBuffer()
672
692
 
693
+ # Show TUNACODE.md preview if it was loaded and thoughts are enabled
694
+ if state_manager.session.show_thoughts and hasattr(state_manager, "tunacode_preview"):
695
+ from tunacode.ui import console as ui
696
+
697
+ await ui.muted(state_manager.tunacode_preview)
698
+ # Clear the preview after displaying it once
699
+ delattr(state_manager, "tunacode_preview")
700
+
673
701
  # Show what we're sending to the API when thoughts are enabled
674
702
  if state_manager.session.show_thoughts:
675
703
  from tunacode.ui import console as ui
@@ -82,9 +82,13 @@ class ConfigSetup(BaseSetup):
82
82
  ):
83
83
  self.state_manager.session.user_config = {}
84
84
  self.state_manager.session.user_config = DEFAULT_USER_CONFIG.copy()
85
- user_configuration.save_config(
86
- self.state_manager
87
- ) # Save the default config initially
85
+ try:
86
+ user_configuration.save_config(
87
+ self.state_manager
88
+ ) # Save the default config initially
89
+ except ConfigurationError as e:
90
+ await ui.error(str(e))
91
+ raise
88
92
  await self._onboarding()
89
93
  else:
90
94
  # No config found - show CLI usage instead of onboarding
@@ -172,11 +176,12 @@ class ConfigSetup(BaseSetup):
172
176
  # Compare configs to see if anything changed
173
177
  current_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
174
178
  if initial_config != current_config:
175
- if user_configuration.save_config(self.state_manager):
179
+ try:
180
+ user_configuration.save_config(self.state_manager)
176
181
  message = f"Config saved to: [bold]{self.config_file}[/bold]"
177
182
  await ui.panel("Finished", message, top=0, border_style=UI_COLORS["success"])
178
- else:
179
- await ui.error("Failed to save configuration.")
183
+ except ConfigurationError as e:
184
+ await ui.error(str(e))
180
185
  else:
181
186
  await ui.panel(
182
187
  "Setup canceled",
@@ -320,8 +325,9 @@ class ConfigSetup(BaseSetup):
320
325
  ]
321
326
 
322
327
  # Save the configuration
323
- if user_configuration.save_config(self.state_manager):
328
+ try:
329
+ user_configuration.save_config(self.state_manager)
324
330
  await ui.warning("Model set without validation - verify the model name is correct")
325
331
  await ui.success(f"Configuration saved to: {self.config_file}")
326
- else:
327
- await ui.error("Failed to save configuration.")
332
+ except ConfigurationError as e:
333
+ await ui.error(str(e))
@@ -58,11 +58,23 @@ def save_config(state_manager: "StateManager") -> bool:
58
58
  """Save user config to file"""
59
59
  app_settings = ApplicationSettings()
60
60
  try:
61
+ # Ensure config directory exists
62
+ app_settings.paths.config_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
63
+
64
+ # Write config file
61
65
  with open(app_settings.paths.config_file, "w") as f:
62
66
  json.dump(state_manager.session.user_config, f, indent=4)
63
67
  return True
64
- except Exception:
65
- return False
68
+ except PermissionError as e:
69
+ raise ConfigurationError(
70
+ f"Permission denied writing to {app_settings.paths.config_file}: {e}"
71
+ )
72
+ except OSError as e:
73
+ raise ConfigurationError(
74
+ f"Failed to save configuration to {app_settings.paths.config_file}: {e}"
75
+ )
76
+ except Exception as e:
77
+ raise ConfigurationError(f"Unexpected error saving configuration: {e}")
66
78
 
67
79
 
68
80
  def get_mcp_servers(state_manager: "StateManager") -> MCPServers:
@@ -73,4 +85,9 @@ def get_mcp_servers(state_manager: "StateManager") -> MCPServers:
73
85
  def set_default_model(model_name: ModelName, state_manager: "StateManager") -> bool:
74
86
  """Set the default model in the user config and save"""
75
87
  state_manager.session.user_config["default_model"] = model_name
76
- return save_config(state_manager)
88
+ try:
89
+ save_config(state_manager)
90
+ return True
91
+ except ConfigurationError:
92
+ # Re-raise ConfigurationError to be handled by caller
93
+ raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tunacode-cli
3
- Version: 0.0.33
3
+ Version: 0.0.34
4
4
  Summary: Your agentic CLI developer.
5
5
  Author-email: larock22 <noreply@github.com>
6
6
  License-Expression: MIT
@@ -40,6 +40,7 @@ Dynamic: license-file
40
40
  <div align="center">
41
41
 
42
42
  [![PyPI version](https://badge.fury.io/py/tunacode-cli.svg)](https://badge.fury.io/py/tunacode-cli)
43
+ [![Downloads](https://pepy.tech/badge/tunacode-cli)](https://pepy.tech/project/tunacode-cli)
43
44
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
44
45
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
46
 
@@ -78,6 +79,17 @@ tunacode --model "openrouter:openai/gpt-4o" --key "sk-or-your-openrouter-key"
78
79
 
79
80
  Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.config/tunacode.json`)
80
81
 
82
+ ### Recommended Models
83
+
84
+ Based on extensive testing, these models provide the best performance:
85
+ - `google/gemini-2.5-pro` - Excellent for complex reasoning
86
+ - `openai/gpt-4.1` - Strong general-purpose model
87
+ - `deepseek/deepseek-r1-0528` - Great for code generation
88
+ - `openai/gpt-4.1-mini` - Fast and cost-effective
89
+ - `anthropic/claude-4-sonnet-20250522` - Superior context handling
90
+
91
+ *Note: Formal evaluations coming soon. Any model can work, but these have shown the best results in practice.*
92
+
81
93
  ## Start Coding
82
94
 
83
95
  ```bash
@@ -105,6 +117,13 @@ TunaCode leverages parallel execution for read-only operations, achieving **3x f
105
117
 
106
118
  Multiple file reads, directory listings, and searches execute concurrently using async I/O, making code exploration significantly faster.
107
119
 
120
+ ## Features in Development
121
+
122
+ - **Streaming UI**: Currently working on implementing streaming responses for better user experience
123
+ - **Bug Fixes**: Actively addressing issues - please report any bugs you encounter!
124
+
125
+ *Note: While the tool is fully functional, we're focusing on stability and core features before optimizing for speed.*
126
+
108
127
  ## Safety First
109
128
 
110
129
  ⚠️ **Important**: TunaCode can modify your codebase. Always:
@@ -1,12 +1,12 @@
1
1
  tunacode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- tunacode/constants.py,sha256=8uIqAbJSTPl8AM_40T6vjrqGDJ2OuxpBcqrWpZCEUeg,4074
2
+ tunacode/constants.py,sha256=SIhhV5x1ESvfVaAki0nJ9XVlKZOwwomqIMT73FLyjPY,4074
3
3
  tunacode/context.py,sha256=6sterdRvPOyG3LU0nEAXpBsEPZbO3qtPyTlJBi-_VXE,2612
4
4
  tunacode/exceptions.py,sha256=mTWXuWyr1k16CGLWN2tsthDGi7lbx1JK0ekIqogYDP8,3105
5
5
  tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  tunacode/setup.py,sha256=dYn0NeAxtNIDSogWEmGSyjb9wsr8AonZ8vAo5sw9NIw,1909
7
7
  tunacode/types.py,sha256=BciT-uxnQ44iC-4QiDY72OD23LOtqSyMOuK_N0ttlaA,7676
8
8
  tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
9
- tunacode/cli/commands.py,sha256=U9dP8wbBnSb-J3nKItRCd9wpQz7wD4urBOjLtCvn9Dc,29887
9
+ tunacode/cli/commands.py,sha256=DEEfDVNzDmMRUhA7JfWGh8antnMeb3G6LmaJLqNVsoI,31293
10
10
  tunacode/cli/main.py,sha256=PIcFnfmIoI_pmK2y-zB_ouJbzR5fbSI7zsKQNPB_J8o,2406
11
11
  tunacode/cli/repl.py,sha256=o3bn9BYQsy3TFCWJq-fzeHKLrM2KInSrMF5E5_RqSOY,13736
12
12
  tunacode/cli/textual_app.py,sha256=14-Nt0IIETmyHBrNn9uwSF3EwCcutwTp6gdoKgNm0sY,12593
@@ -20,14 +20,14 @@ tunacode/core/code_index.py,sha256=jgAx3lSWP_DwnyiP5Jkm1YvX4JJyI4teMzlNrJSpEOA,1
20
20
  tunacode/core/state.py,sha256=PHGCGjx_X03I5jO-T1JkREQm4cwYEXQty59JJlnk24c,1608
21
21
  tunacode/core/tool_handler.py,sha256=BPjR013OOO0cLXPdLeL2FDK0ixUwOYu59FfHdcdFhp4,2277
22
22
  tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
23
- tunacode/core/agents/main.py,sha256=bzex6MTucOf95je1XHICSsMRDKew4TUzg9RApceebj4,38203
23
+ tunacode/core/agents/main.py,sha256=-QwKSKoPLdD-JlKPjwMUSxNu_TSrj-pdUleWR2FN-A0,39441
24
24
  tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  tunacode/core/background/manager.py,sha256=rJdl3eDLTQwjbT7VhxXcJbZopCNR3M8ZGMbmeVnwwMc,1126
26
26
  tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  tunacode/core/setup/__init__.py,sha256=lzdpY6rIGf9DDlDBDGFvQZaSOQeFsNglHbkpq1-GtU8,376
28
28
  tunacode/core/setup/agent_setup.py,sha256=trELO8cPnWo36BBnYmXDEnDPdhBg0p-VLnx9A8hSSSQ,1401
29
29
  tunacode/core/setup/base.py,sha256=cbyT2-xK2mWgH4EO17VfM_OM2bj0kT895NW2jSXbe3c,968
30
- tunacode/core/setup/config_setup.py,sha256=A1MEbkZq2FvVg9FNlLD9_JO_vlr0ixP-6Ay0-2W7VvQ,14330
30
+ tunacode/core/setup/config_setup.py,sha256=LnIGZrqDCWUhiMhJMnKX1gyaZhy6pKM8xf_fy_t9B3U,14516
31
31
  tunacode/core/setup/coordinator.py,sha256=oVTN2xIeJERXitVJpkIk9tDGLs1D1bxIRmaogJwZJFI,2049
32
32
  tunacode/core/setup/environment_setup.py,sha256=n3IrObKEynHZSwtUJ1FddMg2C4sHz7ca42awemImV8s,2225
33
33
  tunacode/core/setup/git_safety_setup.py,sha256=CRIqrQt0QUJQRS344njty_iCqTorrDhHlXRuET7w0Tk,6714
@@ -67,10 +67,10 @@ tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
67
67
  tunacode/utils/system.py,sha256=FSoibTIH0eybs4oNzbYyufIiV6gb77QaeY2yGqW39AY,11381
68
68
  tunacode/utils/text_utils.py,sha256=zRBaorvtyd7HBEWtIfCH1Wce1L6rhsQwpORUEGBFMjA,2981
69
69
  tunacode/utils/token_counter.py,sha256=nGCWwrHHFbKywqeDCEuJnADCkfJuzysWiB6cCltJOKI,648
70
- tunacode/utils/user_configuration.py,sha256=IGvUH37wWtZ4M5xpukZEWYhtuKKyKcl6DaeObGXdleU,2610
71
- tunacode_cli-0.0.33.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
72
- tunacode_cli-0.0.33.dist-info/METADATA,sha256=vf_6TFB9fo7MDRHtXDvLKPys_W4E6t_vzNp-cPpRocQ,4023
73
- tunacode_cli-0.0.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
- tunacode_cli-0.0.33.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
75
- tunacode_cli-0.0.33.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
76
- tunacode_cli-0.0.33.dist-info/RECORD,,
70
+ tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
71
+ tunacode_cli-0.0.34.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
72
+ tunacode_cli-0.0.34.dist-info/METADATA,sha256=uZKr-BnaxT_7vB1gTSIMEnWx1tfOSbBtPAt7gY4pibY,4943
73
+ tunacode_cli-0.0.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
+ tunacode_cli-0.0.34.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
75
+ tunacode_cli-0.0.34.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
76
+ tunacode_cli-0.0.34.dist-info/RECORD,,