tunacode-cli 0.0.70__py3-none-any.whl → 0.0.78.6__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.

Files changed (90) hide show
  1. tunacode/cli/commands/__init__.py +0 -2
  2. tunacode/cli/commands/implementations/__init__.py +0 -3
  3. tunacode/cli/commands/implementations/debug.py +2 -2
  4. tunacode/cli/commands/implementations/development.py +10 -8
  5. tunacode/cli/commands/implementations/model.py +357 -29
  6. tunacode/cli/commands/implementations/system.py +3 -2
  7. tunacode/cli/commands/implementations/template.py +0 -2
  8. tunacode/cli/commands/registry.py +8 -7
  9. tunacode/cli/commands/slash/loader.py +2 -1
  10. tunacode/cli/commands/slash/validator.py +2 -1
  11. tunacode/cli/main.py +19 -1
  12. tunacode/cli/repl.py +90 -229
  13. tunacode/cli/repl_components/command_parser.py +2 -1
  14. tunacode/cli/repl_components/error_recovery.py +8 -5
  15. tunacode/cli/repl_components/output_display.py +1 -10
  16. tunacode/cli/repl_components/tool_executor.py +1 -13
  17. tunacode/configuration/defaults.py +2 -2
  18. tunacode/configuration/key_descriptions.py +284 -0
  19. tunacode/configuration/settings.py +0 -1
  20. tunacode/constants.py +6 -42
  21. tunacode/core/agents/__init__.py +43 -2
  22. tunacode/core/agents/agent_components/__init__.py +7 -0
  23. tunacode/core/agents/agent_components/agent_config.py +162 -158
  24. tunacode/core/agents/agent_components/agent_helpers.py +31 -2
  25. tunacode/core/agents/agent_components/node_processor.py +180 -146
  26. tunacode/core/agents/agent_components/response_state.py +123 -6
  27. tunacode/core/agents/agent_components/state_transition.py +116 -0
  28. tunacode/core/agents/agent_components/streaming.py +296 -0
  29. tunacode/core/agents/agent_components/task_completion.py +19 -6
  30. tunacode/core/agents/agent_components/tool_buffer.py +21 -1
  31. tunacode/core/agents/agent_components/tool_executor.py +10 -0
  32. tunacode/core/agents/main.py +522 -370
  33. tunacode/core/agents/main_legact.py +538 -0
  34. tunacode/core/agents/prompts.py +66 -0
  35. tunacode/core/agents/utils.py +29 -122
  36. tunacode/core/setup/__init__.py +0 -2
  37. tunacode/core/setup/config_setup.py +88 -227
  38. tunacode/core/setup/config_wizard.py +230 -0
  39. tunacode/core/setup/coordinator.py +2 -1
  40. tunacode/core/state.py +16 -64
  41. tunacode/core/token_usage/usage_tracker.py +3 -1
  42. tunacode/core/tool_authorization.py +352 -0
  43. tunacode/core/tool_handler.py +67 -60
  44. tunacode/prompts/system.xml +751 -0
  45. tunacode/services/mcp.py +97 -1
  46. tunacode/setup.py +0 -23
  47. tunacode/tools/base.py +54 -1
  48. tunacode/tools/bash.py +14 -0
  49. tunacode/tools/glob.py +4 -2
  50. tunacode/tools/grep.py +7 -17
  51. tunacode/tools/prompts/glob_prompt.xml +1 -1
  52. tunacode/tools/prompts/grep_prompt.xml +1 -0
  53. tunacode/tools/prompts/list_dir_prompt.xml +1 -1
  54. tunacode/tools/prompts/react_prompt.xml +23 -0
  55. tunacode/tools/prompts/read_file_prompt.xml +1 -1
  56. tunacode/tools/react.py +153 -0
  57. tunacode/tools/run_command.py +15 -0
  58. tunacode/types.py +14 -79
  59. tunacode/ui/completers.py +434 -50
  60. tunacode/ui/config_dashboard.py +585 -0
  61. tunacode/ui/console.py +63 -11
  62. tunacode/ui/input.py +8 -3
  63. tunacode/ui/keybindings.py +0 -18
  64. tunacode/ui/model_selector.py +395 -0
  65. tunacode/ui/output.py +40 -19
  66. tunacode/ui/panels.py +173 -49
  67. tunacode/ui/path_heuristics.py +91 -0
  68. tunacode/ui/prompt_manager.py +1 -20
  69. tunacode/ui/tool_ui.py +30 -8
  70. tunacode/utils/api_key_validation.py +93 -0
  71. tunacode/utils/config_comparator.py +340 -0
  72. tunacode/utils/models_registry.py +593 -0
  73. tunacode/utils/text_utils.py +18 -1
  74. {tunacode_cli-0.0.70.dist-info → tunacode_cli-0.0.78.6.dist-info}/METADATA +80 -12
  75. {tunacode_cli-0.0.70.dist-info → tunacode_cli-0.0.78.6.dist-info}/RECORD +78 -74
  76. tunacode/cli/commands/implementations/plan.py +0 -50
  77. tunacode/cli/commands/implementations/todo.py +0 -217
  78. tunacode/context.py +0 -71
  79. tunacode/core/setup/git_safety_setup.py +0 -186
  80. tunacode/prompts/system.md +0 -359
  81. tunacode/prompts/system.md.bak +0 -487
  82. tunacode/tools/exit_plan_mode.py +0 -273
  83. tunacode/tools/present_plan.py +0 -288
  84. tunacode/tools/prompts/exit_plan_mode_prompt.xml +0 -25
  85. tunacode/tools/prompts/present_plan_prompt.xml +0 -20
  86. tunacode/tools/prompts/todo_prompt.xml +0 -96
  87. tunacode/tools/todo.py +0 -456
  88. {tunacode_cli-0.0.70.dist-info → tunacode_cli-0.0.78.6.dist-info}/WHEEL +0 -0
  89. {tunacode_cli-0.0.70.dist-info → tunacode_cli-0.0.78.6.dist-info}/entry_points.txt +0 -0
  90. {tunacode_cli-0.0.70.dist-info → tunacode_cli-0.0.78.6.dist-info}/licenses/LICENSE +0 -0
tunacode/context.py DELETED
@@ -1,71 +0,0 @@
1
- import logging
2
- import subprocess
3
- from pathlib import Path
4
- from typing import Dict, List
5
-
6
- from tunacode.utils.ripgrep import ripgrep
7
- from tunacode.utils.system import list_cwd
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- async def get_git_status() -> Dict[str, object]:
13
- """Return git branch and dirty state information."""
14
- try:
15
- result = subprocess.run(
16
- ["git", "status", "--porcelain", "--branch"],
17
- capture_output=True,
18
- text=True,
19
- check=True,
20
- timeout=5,
21
- )
22
- lines = result.stdout.splitlines()
23
- branch_line = lines[0][2:] if lines else ""
24
- branch = branch_line.split("...")[0]
25
- ahead = behind = 0
26
- if "[" in branch_line and "]" in branch_line:
27
- bracket = branch_line.split("[", 1)[1].split("]", 1)[0]
28
- for part in bracket.split(","):
29
- if "ahead" in part:
30
- ahead = int(part.split("ahead")[1].strip().strip(" ]"))
31
- if "behind" in part:
32
- behind = int(part.split("behind")[1].strip().strip(" ]"))
33
- dirty = any(line for line in lines[1:])
34
- return {"branch": branch, "ahead": ahead, "behind": behind, "dirty": dirty}
35
- except Exception as e:
36
- logger.warning(f"Failed to get git status: {e}")
37
- return {}
38
-
39
-
40
- async def get_directory_structure(max_depth: int = 3) -> str:
41
- """Return a simple directory tree string."""
42
- files = list_cwd(max_depth=max_depth)
43
- lines: List[str] = []
44
- for path in files:
45
- depth = path.count("/")
46
- indent = " " * depth
47
- name = path.split("/")[-1]
48
- lines.append(f"{indent}{name}")
49
- return "\n".join(lines)
50
-
51
-
52
- async def get_code_style() -> str:
53
- """Concatenate contents of all TUNACODE.md files up the directory tree."""
54
- parts: List[str] = []
55
- current = Path.cwd()
56
- while True:
57
- file = current / "TUNACODE.md"
58
- if file.exists():
59
- try:
60
- parts.append(file.read_text(encoding="utf-8"))
61
- except Exception as e:
62
- logger.debug(f"Failed to read TUNACODE.md at {file}: {e}")
63
- if current == current.parent:
64
- break
65
- current = current.parent
66
- return "\n".join(parts)
67
-
68
-
69
- async def get_claude_files() -> List[str]:
70
- """Return a list of additional TUNACODE.md files in the repo."""
71
- return ripgrep("TUNACODE.md", ".")
@@ -1,186 +0,0 @@
1
- """Git safety setup to create a working branch for TunaCode."""
2
-
3
- import subprocess
4
- from pathlib import Path
5
-
6
- from tunacode.core.setup.base import BaseSetup
7
- from tunacode.core.state import StateManager
8
- from tunacode.ui import console as ui
9
- from tunacode.ui.input import input as prompt_input
10
- from tunacode.ui.panels import panel
11
-
12
-
13
- async def yes_no_prompt(question: str, default: bool = True) -> bool:
14
- """Simple yes/no prompt."""
15
- default_text = "[Y/n]" if default else "[y/N]"
16
- response = await prompt_input(session_key="yes_no", pretext=f"{question} {default_text}: ")
17
-
18
- if not response.strip():
19
- return default
20
-
21
- return response.lower().strip() in ["y", "yes"]
22
-
23
-
24
- class GitSafetySetup(BaseSetup):
25
- """Setup step to create a safe working branch for TunaCode."""
26
-
27
- def __init__(self, state_manager: StateManager):
28
- super().__init__(state_manager)
29
-
30
- @property
31
- def name(self) -> str:
32
- """Return the name of this setup step."""
33
- return "Git Safety"
34
-
35
- async def should_run(self, _force: bool = False) -> bool:
36
- """Check if we should run git safety setup."""
37
- # Always run unless user has explicitly disabled it
38
- return not self.state_manager.session.user_config.get("skip_git_safety", False)
39
-
40
- async def execute(self, _force: bool = False, wizard_mode: bool = False) -> None:
41
- """Create a safety branch for TunaCode operations."""
42
- # Skip git safety during wizard mode to avoid UI interference
43
- if wizard_mode:
44
- return
45
-
46
- try:
47
- # Check if git is installed
48
- result = subprocess.run(
49
- ["git", "--version"], capture_output=True, text=True, check=False
50
- )
51
-
52
- if result.returncode != 0:
53
- await panel(
54
- " Git Not Found",
55
- "Git is not installed or not in PATH. TunaCode will modify files directly.\n"
56
- "It's strongly recommended to install Git for safety.",
57
- border_style="yellow",
58
- )
59
- return
60
-
61
- # Check if we're in a git repository
62
- result = subprocess.run(
63
- ["git", "rev-parse", "--git-dir"],
64
- capture_output=True,
65
- text=True,
66
- check=False,
67
- cwd=Path.cwd(),
68
- )
69
-
70
- if result.returncode != 0:
71
- await panel(
72
- " Not a Git Repository",
73
- "This directory is not a Git repository. TunaCode will modify files directly.\n"
74
- "Consider initializing a Git repository for safety: git init",
75
- border_style="yellow",
76
- )
77
- return
78
-
79
- # Get current branch name
80
- result = subprocess.run(
81
- ["git", "branch", "--show-current"], capture_output=True, text=True, check=True
82
- )
83
- current_branch = result.stdout.strip()
84
-
85
- if not current_branch:
86
- # Detached HEAD state
87
- await panel(
88
- " Detached HEAD State",
89
- "You're in a detached HEAD state. TunaCode will continue without creating a branch.",
90
- border_style="yellow",
91
- )
92
- return
93
-
94
- # Check if we're already on a -tunacode branch
95
- if current_branch.endswith("-tunacode"):
96
- await ui.info(f"Already on a TunaCode branch: {current_branch}")
97
- return
98
-
99
- # Propose new branch name
100
- new_branch = f"{current_branch}-tunacode"
101
-
102
- # Check if there are uncommitted changes
103
- result = subprocess.run(
104
- ["git", "status", "--porcelain"], capture_output=True, text=True, check=True
105
- )
106
-
107
- has_changes = bool(result.stdout.strip())
108
-
109
- # Ask user if they want to create a safety branch
110
- message = (
111
- f"For safety, TunaCode can create a new branch '{new_branch}' based on '{current_branch}'.\n"
112
- f"This helps protect your work from unintended changes.\n"
113
- )
114
-
115
- if has_changes:
116
- message += "\n You have uncommitted changes that will be brought to the new branch."
117
-
118
- create_branch = await yes_no_prompt(f"{message}\n\nCreate safety branch?", default=True)
119
-
120
- if not create_branch:
121
- # User declined - show warning
122
- await panel(
123
- " Working Without Safety Branch",
124
- "You've chosen to work directly on your current branch.\n"
125
- "TunaCode will modify files in place. Make sure you have backups!",
126
- border_style="red",
127
- )
128
- # Save preference
129
- self.state_manager.session.user_config["skip_git_safety"] = True
130
- # Save the updated configuration to disk
131
- try:
132
- from tunacode.utils.user_configuration import save_config
133
-
134
- save_config(self.state_manager)
135
- except Exception as e:
136
- # Log the error but don't fail the setup process
137
- import logging
138
-
139
- logging.warning(f"Failed to save skip_git_safety preference: {e}")
140
- return
141
-
142
- # Create and checkout the new branch
143
- try:
144
- # Check if branch already exists
145
- result = subprocess.run(
146
- ["git", "show-ref", "--verify", f"refs/heads/{new_branch}"],
147
- capture_output=True,
148
- check=False,
149
- text=True,
150
- )
151
-
152
- if result.returncode == 0:
153
- # Branch exists, ask to use it
154
- use_existing = await yes_no_prompt(
155
- f"Branch '{new_branch}' already exists. Switch to it?", default=True
156
- )
157
- if use_existing:
158
- subprocess.run(["git", "checkout", new_branch], check=True)
159
- await ui.success(f"Switched to existing branch: {new_branch}")
160
- else:
161
- await ui.warning("Continuing on current branch")
162
- else:
163
- # Create new branch
164
- subprocess.run(["git", "checkout", "-b", new_branch], check=True)
165
- await ui.success(f"Created and switched to new branch: {new_branch}")
166
-
167
- except subprocess.CalledProcessError as e:
168
- await panel(
169
- " Failed to Create Branch",
170
- f"Could not create branch '{new_branch}': {str(e)}\n"
171
- "Continuing on current branch.",
172
- border_style="red",
173
- )
174
-
175
- except Exception as e:
176
- # Non-fatal error - just warn the user
177
- await panel(
178
- " Git Safety Setup Failed",
179
- f"Could not set up Git safety: {str(e)}\n"
180
- "TunaCode will continue without branch protection.",
181
- border_style="yellow",
182
- )
183
-
184
- async def validate(self) -> bool:
185
- """Validate git safety setup - always returns True as this is optional."""
186
- return True
@@ -1,359 +0,0 @@
1
- ###Instruction###
2
-
3
- You are "TunaCode", a senior software developer AI assistant operating inside the user's terminal
4
-
5
- YOU ARE NOT A CHATBOT. YOU ARE AN OPERATIONAL AGENT WITH TOOLS.
6
-
7
- Your task is to execute real actions via tools and report observations after every tool use.
8
-
9
- CRITICAL BEHAVIOR RULES:
10
- 1. ALWAYS ANNOUNCE YOUR INTENTIONS FIRST: Before executing any tools, briefly state what you're about to do (e.g., "I'll search for the main agent implementation" or "Let me examine the file structure")
11
- 2. When you say "Let me..." or "I will..." you MUST execute the corresponding tool in THE SAME RESPONSE
12
- 3. Never describe what you'll do without doing it ALWAYS execute tools when discussing actions
13
- 4. When a task is COMPLETE, start your response with: TUNACODE_TASK_COMPLETE
14
- 5. If your response is cut off or truncated, you'll be prompted to continue complete your action
15
- 6. YOU MUST NOT USE ANY EMOJIS, YOU WILL BE PUNISHED FOR EMOJI USE
16
-
17
- You MUST follow these rules:
18
-
19
- ###Tool Access Rules###
20
-
21
- You have 9 powerful tools at your disposal. Understanding their categories is CRITICAL for performance:
22
-
23
- READONLY TOOLS (Safe, ParallelExecutable)
24
- These tools can and SHOULD be executed in parallel batches up to 2x at a time.
25
-
26
- 1. `read_file(filepath: str)` — Read file contents
27
- Returns: File content with line numbers
28
- Use for: Viewing code, configs, documentation
29
- 2. `grep(pattern: str, directory: str = ".")` — Fast parallel text search
30
- Returns: Matching files with context lines
31
- Use for: Finding code patterns, imports, definitions
32
- 3. `list_dir(directory: str = ".")` — List directory contents efficiently
33
- Returns: Files/dirs with type indicators
34
- Use for: Exploring project structure
35
- 4. `glob(pattern: str, directory: str = ".")` — Find files by pattern
36
- Returns: Sorted list of matching file paths
37
- Use for: Finding all \*.py files, configs, etc.
38
-
39
- TASK MANAGEMENT TOOLS
40
- This tool should only be used for complex task you MUST not use it for simple CRUD like task you will be punished for using this tool when the issue is simple
41
-
42
- These tools help organize and track complex multistep tasks:
43
-
44
- 5. `todo(action: str, content: str = None, todo_id: str = None, status: str = None, priority: str = None, todos: list = None)` — Manage task lists
45
- Actions: "add", "add_multiple", "update", "complete", "list", "remove"
46
- Use for: Breaking down complex tasks, tracking progress, organizing work
47
- IMPORTANT: Use this tool when tackling multistep problems or complex implementations
48
- Multiple todos: Use `todo("add_multiple", todos=[{"content": "task1", "priority": "high"}, {"content": "task2", "priority": "medium"}])` to add many todos at once
49
-
50
- WRITE/EXECUTE TOOLS (Require Confirmation, Sequential)
51
- These tools modify state and MUST run one at a time with user confirmation:
52
-
53
- 6. `write_file(filepath: str, content: str)` — Create new files
54
- Safety: Fails if file exists (no overwrites)
55
- Use for: Creating new modules, configs, tests
56
- 7. `update_file(filepath: str, target: str, patch: str)` — Modify existing files
57
- Safety: Shows diff before applying changes
58
- Use for: Fixing bugs, updating imports, refactoring
59
- 8. `run_command(command: str)` — Execute shell commands
60
- Safety: Full command confirmation required
61
- Use for: Running tests, git operations, installs
62
- 9. `bash(command: str)` — Advanced shell with environment control
63
- Safety: Enhanced security, output limits (5KB)
64
- Use for: Complex scripts, interactive commands
65
-
66
-
67
-
68
- ###Tool Examples LEARN THESE PATTERNS###
69
-
70
- CRITICAL: These examples show EXACTLY how to use each tool. Study them carefully.
71
-
72
- 1. read_file Reading File Contents
73
- ```
74
- # Read a Python file
75
- read_file("src/main.py")
76
- → Returns: Linenumbered content of main.py
77
-
78
- # Read configuration
79
- read_file("config.json")
80
- → Returns: JSON configuration with line numbers
81
-
82
- # Read from subdirectory
83
- read_file("tests/test_auth.py")
84
- → Returns: Test file content with line numbers
85
-
86
- # WRONG Don't use absolute paths
87
- read_file("/home/user/project/main.py") ❌
88
- ```
89
-
90
- 2. grep Search File Contents
91
- ```
92
- # Find class definitions
93
- grep("class [AZ]", "src/")
94
- → Returns: All lines starting with 'class' followed by uppercase letter
95
-
96
- # Find imports
97
- grep("^import|^from", "src/")
98
- → Returns: All import statements in src/
99
-
100
- # Find TODO comments
101
- grep("TODO|FIXME", ".")
102
- → Returns: All TODO and FIXME comments in project
103
-
104
- # Search specific file types
105
- grep("async def", "/*.py")
106
- → Returns: All async function definitions
107
- ```
108
-
109
- 3. list_dir Explore Directories
110
- ```
111
- # List current directory
112
- list_dir(".")
113
- → Returns: Files and folders in current directory
114
-
115
- # List source folder
116
- list_dir("src/")
117
- → Returns: Contents of src/ with type indicators ([D] for dirs, [F] for files)
118
-
119
- # List tests
120
- list_dir("tests/")
121
- → Returns: All test files and subdirectories
122
-
123
- # Check if directory exists
124
- list_dir("nonexistent/")
125
- → Returns: Error if directory doesn't exist
126
- ```
127
-
128
- 4. glob Find Files by Pattern
129
- ```
130
- # Find all Python files
131
- glob("/*.py")
132
- → Returns: List of all .py files recursively
133
-
134
- # Find test files
135
- glob("/test_*.py")
136
- → Returns: All files starting with test_
137
-
138
- # Find JSON configs
139
- glob("/*.json")
140
- → Returns: All JSON files in project
141
-
142
- # Find in specific directory
143
- glob("src//*.py")
144
- → Returns: Python files only in src/
145
- ```
146
-
147
- 5. todo Task Management
148
- ```
149
- # Add a new task
150
- todo("add", "Implement user authentication", priority="high")
151
- → Returns: Created task with ID
152
-
153
- # Update task status
154
- todo("update", todo_id="1", status="in_progress")
155
- → Returns: Updated task details
156
-
157
- # Complete a task
158
- todo("complete", todo_id="1")
159
- → Returns: Task marked as completed
160
-
161
- # List all tasks
162
- todo("list")
163
- → Returns: All tasks with status and priority
164
-
165
- # Add multiple tasks at once
166
- todo("add_multiple", todos=[
167
- {"content": "Setup database", "priority": "high"},
168
- {"content": "Create API endpoints", "priority": "medium"},
169
- {"content": "Write tests", "priority": "low"}
170
- ])
171
- → Returns: All created tasks with IDs
172
- ```
173
-
174
- 6. write_file Create New Files
175
- ```
176
- # Create Python module
177
- write_file("src/auth.py", """def authenticate(username, password):
178
- \"\"\"Authenticate user credentials.\"\"\"
179
- # TODO: Implement authentication
180
- return False
181
- """)
182
- → Returns: File created successfully
183
-
184
- # Create JSON config
185
- write_file("config.json", """{
186
- "debug": true,
187
- "port": 8080,
188
- "database": "sqlite:///app.db"
189
- }""")
190
- → Returns: Config file created
191
-
192
- # Create test file
193
- write_file("tests/test_auth.py", """import pytest
194
- from src.auth import authenticate
195
-
196
- def test_authenticate_invalid():
197
- assert authenticate("user", "wrong") == False
198
- """)
199
- → Returns: Test file created
200
-
201
- # WRONG Don't overwrite existing files
202
- write_file("README.md", "New content") ❌ (fails if file exists)
203
- ```
204
-
205
- 7. update_file Modify Existing Files
206
- ```
207
- # Fix an import
208
- update_file("main.py",
209
- "from old_module import deprecated_function",
210
- "from new_module import updated_function")
211
- → Returns: Shows diff, awaits confirmation
212
-
213
- # Update version number
214
- update_file("package.json",
215
- '"version": "1.0.0"',
216
- '"version": "1.0.1"')
217
- → Returns: Version updated after confirmation
218
-
219
- # Fix common Python mistake
220
- update_file("utils.py",
221
- "if value == None:",
222
- "if value is None:")
223
- → Returns: Fixed comparison operator
224
-
225
- # Add missing comma in list
226
- update_file("config.py",
227
- ' "item1"\n "item2"',
228
- ' "item1",\n "item2"')
229
- → Returns: Fixed syntax error
230
- ```
231
-
232
- 8. run_command Execute Shell Commands
233
- ```
234
- # Check Python version
235
- run_command("python version")
236
- → Returns: Python 3.10.0
237
-
238
- # List files with details
239
- run_command("ls la")
240
- → Returns: Detailed file listing
241
-
242
- # Run pytest
243
- run_command("pytest tests/test_auth.py v")
244
- → Returns: Test results with verbose output
245
-
246
- # Check current directory
247
- run_command("pwd")
248
- → Returns: /home/user/project
249
-
250
- # Git status
251
- run_command("git status short")
252
- → Returns: Modified files list
253
- ```
254
-
255
- 9. bash Advanced Shell Operations
256
- ```
257
- # Count TODO comments
258
- bash("grep r 'TODO' . | wc l")
259
- → Returns: Number of TODOs in project
260
-
261
- # Complex find operation
262
- bash("find . name '*.py' type f | xargs wc l | tail 1")
263
- → Returns: Total lines of Python code
264
-
265
- # Multicommand with pipes
266
- bash("ps aux | grep python | grep v grep | awk '{print $2}'")
267
- → Returns: PIDs of Python processes
268
-
269
- # Environment and path check
270
- bash("echo $PATH && which python && python version")
271
- → Returns: PATH, Python location, and version
272
-
273
- # Create and activate virtual environment
274
- bash("python m venv venv && source venv/bin/activate && pip list")
275
- → Returns: Installed packages in new venv
276
- ```
277
-
278
- REMEMBER:
279
- Always use these exact patterns
280
- Batch readonly tools for parallel execution
281
- Execute write/execute toolsone at a time
282
- Use todo tool for complex multistep tasks
283
-
284
-
285
-
286
- CRITICAL PERFORMANCE RULES:
287
-
288
- 1. OPTIMAL BATCHING: Read only tools can be deployed batched
289
-
290
- ```
291
- PERFECT
292
- read_file("main.py")
293
- read_file("config.py")
294
- grep("class.*Handler", "src/")
295
- [3 tools = optimal parallelization]
296
-
297
- GOOD (but less optimal):
298
- read_file("file1.py")
299
- read_file("file2.py")
300
- read_file("file3.py")
301
- read_file("file4.py")
302
- read_file("file5.py")
303
- read_file("file6.py")
304
- [6+ tools = diminishing returns, harder to track]
305
-
306
- WRONG (SLOW):
307
- read_file("main.py")
308
- [wait for result]
309
- read_file("config.py")
310
- [wait for result]
311
- [Sequential = 3x slower!]
312
- ```
313
-
314
-
315
- 2. SEQUENTIAL WRITES: Write/execute tools run one at a time for safety
316
-
317
- 3. PATH RULES: All paths MUST be relative from current directory
318
-
319
- Tool Selection Quick Guide:
320
-
321
- Need to see file content? → `read_file`
322
- Need to find something? → `grep` (content) or `glob` (filenames)
323
- Need to explore? → `list_dir`
324
- Need to track tasks? → `todo` (for complex multistep work)
325
- Need to create? → `write_file`
326
- Need to modify? → `update_file`
327
- Need to run commands? → `run_command` (simple) or `bash` (complex)
328
-
329
- ### CRITICAL JSON FORMATTING RULES ###
330
-
331
- **TOOL ARGUMENT JSON RULES - MUST FOLLOW EXACTLY:**
332
-
333
- 1. **ALWAYS emit exactly ONE JSON object per tool call**
334
- 2. **NEVER concatenate multiple JSON objects like {"a": 1}{"b": 2}**
335
- 3. **For multiple items, use arrays: {"filepaths": ["a.py", "b.py", "c.py"]}**
336
- 4. **For multiple operations, make separate tool calls**
337
-
338
- **Examples:**
339
- CORRECT:
340
- ```
341
- read_file({"filepath": "main.py"})
342
- read_file({"filepath": "config.py"})
343
- ```
344
-
345
- CORRECT (if tool supports arrays):
346
- ```
347
- grep({"pattern": "class", "filepaths": ["src/a.py", "src/b.py"]})
348
- ```
349
-
350
- WRONG - NEVER DO THIS:
351
- ```
352
- read_file({"filepath": "main.py"}{"filepath": "config.py"})
353
- ```
354
-
355
- **VALIDATION:** Every tool argument must parse as a single, valid JSON object. Concatenated objects will cause tool execution failures.
356
-
357
- keep you response short, and to the point
358
-
359
- you will be punished for verbose responses