gitarsenal-cli 1.9.96 ā 1.9.97
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.
- package/.venv_status.json +1 -1
- package/README.md +29 -0
- package/bin/gitarsenal.js +220 -127
- package/kill_claude/requirements.txt +1 -1
- package/lib/dependencies.js +130 -4
- package/lib/e2b-sandbox.js +158 -0
- package/lib/execAsync.js +12 -0
- package/lib/sandbox.js +97 -113
- package/package.json +2 -1
- package/python/__pycache__/credentials_manager.cpython-312.pyc +0 -0
- package/python/__pycache__/e2b_sandbox_agent.cpython-313.pyc +0 -0
- package/python/__pycache__/fetch_modal_tokens.cpython-312.pyc +0 -0
- package/python/credentials_manager.py +2 -1
- package/python/e2b_sandbox_agent.py +787 -0
- package/python/fetch_modal_tokens.py +47 -25
- package/python/requirements.txt +2 -1
- package/python/test_enhanced_sandbox_script.py +1429 -0
- package/python/test_modalSandboxScript.py +41 -5
- package/scripts/setup_e2b.js +162 -0
- package/kill_claude/.claude/settings.local.json +0 -9
- package/kill_claude/__pycache__/bash_output_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/claude_code_agent.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/exit_plan_mode_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/glob_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/grep_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/kill_bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/ls_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/multiedit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/notebook_edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/read_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/task_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/todo_write_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/web_fetch_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/web_search_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/write_tool.cpython-313.pyc +0 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
E2B Sandbox Runner with Agent for GitArsenal
|
|
4
|
+
-------------------------------------------
|
|
5
|
+
This script creates an E2B sandbox, uploads the kill_claude agent files,
|
|
6
|
+
and runs the agent to set up a repository.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import time
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from e2b_code_interpreter import Sandbox
|
|
17
|
+
|
|
18
|
+
def install_dependencies_in_sandbox(sandbox):
|
|
19
|
+
"""
|
|
20
|
+
Install required packages in the sandbox
|
|
21
|
+
"""
|
|
22
|
+
print("š¦ Installing required packages in sandbox...")
|
|
23
|
+
|
|
24
|
+
# Install Python packages
|
|
25
|
+
packages = [
|
|
26
|
+
"openai",
|
|
27
|
+
"anthropic",
|
|
28
|
+
"python-dotenv",
|
|
29
|
+
"requests",
|
|
30
|
+
"tiktoken",
|
|
31
|
+
"typer",
|
|
32
|
+
"rich"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
for package in packages:
|
|
36
|
+
print(f" š¦ Installing {package}...")
|
|
37
|
+
result = sandbox.commands.run(f"pip install {package}")
|
|
38
|
+
if result.exit_code == 0:
|
|
39
|
+
print(f" ā Installed {package}")
|
|
40
|
+
else:
|
|
41
|
+
print(f" ā Failed to install {package}")
|
|
42
|
+
print(result.stderr)
|
|
43
|
+
|
|
44
|
+
# Check if git is available
|
|
45
|
+
result = sandbox.commands.run("which git")
|
|
46
|
+
if result.exit_code == 0:
|
|
47
|
+
print(" ā Git is already installed")
|
|
48
|
+
else:
|
|
49
|
+
print(" ā Git is not available")
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
print("ā
Dependencies installation completed")
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
def upload_claude_agent_to_sandbox(sandbox):
|
|
56
|
+
"""
|
|
57
|
+
Upload the claude_code_agent.py and related files to the sandbox
|
|
58
|
+
"""
|
|
59
|
+
print("š¤ Uploading claude_code_agent.py and related files...")
|
|
60
|
+
|
|
61
|
+
# Create necessary directories
|
|
62
|
+
sandbox.commands.run("mkdir -p /home/user/kill_claude/tools")
|
|
63
|
+
sandbox.commands.run("mkdir -p /home/user/kill_claude/prompts")
|
|
64
|
+
|
|
65
|
+
# Find the kill_claude directory path
|
|
66
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
67
|
+
gitarsenal_root = os.path.dirname(script_dir)
|
|
68
|
+
kill_claude_dir = os.path.join(gitarsenal_root, "kill_claude")
|
|
69
|
+
|
|
70
|
+
if not os.path.exists(kill_claude_dir):
|
|
71
|
+
print(f"ā Could not find kill_claude directory at {kill_claude_dir}")
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
# Upload claude_code_agent.py
|
|
75
|
+
agent_path = os.path.join(kill_claude_dir, "claude_code_agent.py")
|
|
76
|
+
if os.path.exists(agent_path):
|
|
77
|
+
with open(agent_path, "r") as f:
|
|
78
|
+
agent_content = f.read()
|
|
79
|
+
|
|
80
|
+
# Check for common issues and fix them
|
|
81
|
+
print("Checking for common issues in claude_code_agent.py...")
|
|
82
|
+
|
|
83
|
+
# Ensure it has the proper shebang
|
|
84
|
+
if not agent_content.startswith("#!/usr/bin/env python"):
|
|
85
|
+
agent_content = "#!/usr/bin/env python3\n" + agent_content
|
|
86
|
+
print(" ā Added shebang to claude_code_agent.py")
|
|
87
|
+
|
|
88
|
+
# Check for API key environment variable access
|
|
89
|
+
if "os.environ['ANTHROPIC_API_KEY']" in agent_content and "os.environ.get('ANTHROPIC_API_KEY')" not in agent_content:
|
|
90
|
+
agent_content = agent_content.replace(
|
|
91
|
+
"os.environ['ANTHROPIC_API_KEY']",
|
|
92
|
+
"os.environ.get('ANTHROPIC_API_KEY')"
|
|
93
|
+
)
|
|
94
|
+
print(" ā Fixed API key access to use os.environ.get()")
|
|
95
|
+
|
|
96
|
+
# Check for the correct model name
|
|
97
|
+
if "claude-3-5-sonnet" in agent_content and "claude-3-5-sonnet-20241022" not in agent_content:
|
|
98
|
+
agent_content = agent_content.replace(
|
|
99
|
+
"claude-3-5-sonnet",
|
|
100
|
+
"claude-3-5-sonnet-20241022"
|
|
101
|
+
)
|
|
102
|
+
print(" ā Updated model name to claude-3-5-sonnet-20241022")
|
|
103
|
+
|
|
104
|
+
# Check if it's using Typer correctly
|
|
105
|
+
if "app = typer.Typer()" in agent_content and "if __name__ == \"__main__\":" in agent_content:
|
|
106
|
+
# Make sure the main function is called correctly
|
|
107
|
+
if "if __name__ == \"__main__\":\n app()" not in agent_content and "if __name__ == \"__main__\":\n main()" in agent_content:
|
|
108
|
+
agent_content = agent_content.replace(
|
|
109
|
+
"if __name__ == \"__main__\":\n main()",
|
|
110
|
+
"if __name__ == \"__main__\":\n app()"
|
|
111
|
+
)
|
|
112
|
+
print(" ā Fixed Typer app execution")
|
|
113
|
+
|
|
114
|
+
sandbox.run_code(f"""
|
|
115
|
+
with open('/home/user/kill_claude/claude_code_agent.py', 'w') as f:
|
|
116
|
+
f.write({repr(agent_content)})
|
|
117
|
+
""")
|
|
118
|
+
print(" ā Uploaded claude_code_agent.py with fixes")
|
|
119
|
+
|
|
120
|
+
# Ensure the first line has the shebang
|
|
121
|
+
sandbox.run_code("""
|
|
122
|
+
content = ''
|
|
123
|
+
with open('/home/user/kill_claude/claude_code_agent.py', 'r') as f:
|
|
124
|
+
content = f.read()
|
|
125
|
+
if not content.startswith('#!/usr/bin/env python'):
|
|
126
|
+
with open('/home/user/kill_claude/claude_code_agent.py', 'w') as f:
|
|
127
|
+
f.write('#!/usr/bin/env python3\\n' + content)
|
|
128
|
+
print(" ā Added shebang to claude_code_agent.py")
|
|
129
|
+
""")
|
|
130
|
+
else:
|
|
131
|
+
print(f"ā Could not find claude_code_agent.py at {agent_path}")
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
# Upload requirements.txt
|
|
135
|
+
req_path = os.path.join(kill_claude_dir, "requirements.txt")
|
|
136
|
+
if os.path.exists(req_path):
|
|
137
|
+
with open(req_path, "r") as f:
|
|
138
|
+
req_content = f.read()
|
|
139
|
+
sandbox.run_code(f"""
|
|
140
|
+
with open('/home/user/kill_claude/requirements.txt', 'w') as f:
|
|
141
|
+
f.write({repr(req_content)})
|
|
142
|
+
""")
|
|
143
|
+
print(" ā Uploaded requirements.txt")
|
|
144
|
+
|
|
145
|
+
# Upload prompts
|
|
146
|
+
prompts_dir = os.path.join(kill_claude_dir, "prompts")
|
|
147
|
+
if os.path.exists(prompts_dir):
|
|
148
|
+
for prompt_file in os.listdir(prompts_dir):
|
|
149
|
+
if prompt_file.endswith(".md"):
|
|
150
|
+
prompt_path = os.path.join(prompts_dir, prompt_file)
|
|
151
|
+
with open(prompt_path, "r") as f:
|
|
152
|
+
prompt_content = f.read()
|
|
153
|
+
sandbox.run_code(f"""
|
|
154
|
+
with open('/home/user/kill_claude/prompts/{prompt_file}', 'w') as f:
|
|
155
|
+
f.write({repr(prompt_content)})
|
|
156
|
+
""")
|
|
157
|
+
print(f"Preparing Agents...")
|
|
158
|
+
|
|
159
|
+
# Upload tools
|
|
160
|
+
tools_dir = os.path.join(kill_claude_dir, "tools")
|
|
161
|
+
if os.path.exists(tools_dir):
|
|
162
|
+
for tool_file in os.listdir(tools_dir):
|
|
163
|
+
if tool_file.endswith(".py"):
|
|
164
|
+
tool_path = os.path.join(tools_dir, tool_file)
|
|
165
|
+
with open(tool_path, "r") as f:
|
|
166
|
+
tool_content = f.read()
|
|
167
|
+
sandbox.run_code(f"""
|
|
168
|
+
with open('/home/user/kill_claude/tools/{tool_file}', 'w') as f:
|
|
169
|
+
f.write({repr(tool_content)})
|
|
170
|
+
""")
|
|
171
|
+
print(f"Preparing Tools...")
|
|
172
|
+
|
|
173
|
+
# Create __init__.py in tools directory
|
|
174
|
+
sandbox.run_code("""
|
|
175
|
+
with open('/home/user/kill_claude/tools/__init__.py', 'w') as f:
|
|
176
|
+
f.write('')
|
|
177
|
+
""")
|
|
178
|
+
|
|
179
|
+
print("ā
Agents are ready to go!")
|
|
180
|
+
return True
|
|
181
|
+
|
|
182
|
+
def create_simple_agent_script(sandbox):
|
|
183
|
+
"""
|
|
184
|
+
Create a simpler agent script that emulates the TodoWrite functionality
|
|
185
|
+
"""
|
|
186
|
+
print("š Creating simple agent script...")
|
|
187
|
+
|
|
188
|
+
script_content = """
|
|
189
|
+
import os
|
|
190
|
+
import sys
|
|
191
|
+
import subprocess
|
|
192
|
+
import time
|
|
193
|
+
import json
|
|
194
|
+
|
|
195
|
+
def run_command(cmd, cwd=None):
|
|
196
|
+
print(f"Running: {cmd}")
|
|
197
|
+
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=cwd)
|
|
198
|
+
if result.stdout:
|
|
199
|
+
print("Output:")
|
|
200
|
+
print(result.stdout.strip())
|
|
201
|
+
if result.stderr:
|
|
202
|
+
print("Error:")
|
|
203
|
+
print(result.stderr.strip())
|
|
204
|
+
return result.returncode == 0, result.stdout
|
|
205
|
+
|
|
206
|
+
def print_todo_list(todos):
|
|
207
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāā š ļø Using Tool: TodoWrite āāāāāāāāāāāāāāāāāāāāāāāāāāāā®")
|
|
208
|
+
print("ā āāāāāāāāāāāāāāāāāāāāāāāāāāā Todo List ({} items) āāāāāāāāāāāāāāāāāāāāāāāāāāāā® ā".format(len(todos)))
|
|
209
|
+
print("ā ā āāāāāāā³āāāāāāāāāāāāā³āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā ā")
|
|
210
|
+
print("ā ā ā # ā Status ā Task ā ā ā")
|
|
211
|
+
print("ā ā ā”āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā© ā ā")
|
|
212
|
+
|
|
213
|
+
for i, todo in enumerate(todos, 1):
|
|
214
|
+
status = "ā³ Pending"
|
|
215
|
+
if todo.get("status") == "in_progress":
|
|
216
|
+
status = "š In Progress"
|
|
217
|
+
elif todo.get("status") == "completed":
|
|
218
|
+
status = "ā Completed"
|
|
219
|
+
|
|
220
|
+
content = todo.get("content", "")
|
|
221
|
+
print("ā ā ā {:<3} ā {:<10} ā {:<50} ā ā ā".format(i, status, content[:50]))
|
|
222
|
+
|
|
223
|
+
print("ā ā āāāāāāā“āāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā ā")
|
|
224
|
+
print("ā ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā⯠ā")
|
|
225
|
+
print("ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ")
|
|
226
|
+
|
|
227
|
+
def update_todo(todos, index, status):
|
|
228
|
+
if 0 <= index < len(todos):
|
|
229
|
+
todos[index]["status"] = status
|
|
230
|
+
return todos
|
|
231
|
+
|
|
232
|
+
def setup_repository(repo_url):
|
|
233
|
+
print("Setting up repository: " + repo_url)
|
|
234
|
+
|
|
235
|
+
# Initialize todo list
|
|
236
|
+
todos = [
|
|
237
|
+
{"id": "1", "content": "Clone the repository from GitHub", "status": "pending"},
|
|
238
|
+
{"id": "2", "content": "Examine repository structure and setup requirements", "status": "pending"},
|
|
239
|
+
{"id": "3", "content": "Install dependencies and setup the project", "status": "pending"},
|
|
240
|
+
{"id": "4", "content": "Run the application/tests", "status": "pending"},
|
|
241
|
+
{"id": "5", "content": "Print ordered list of successful commands", "status": "pending"}
|
|
242
|
+
]
|
|
243
|
+
|
|
244
|
+
print_todo_list(todos)
|
|
245
|
+
|
|
246
|
+
# Step 1: Clone repository
|
|
247
|
+
print("\\n============================================================")
|
|
248
|
+
print("š AGENT OUTPUT (LIVE)")
|
|
249
|
+
print("============================================================")
|
|
250
|
+
|
|
251
|
+
todos = update_todo(todos, 0, "in_progress")
|
|
252
|
+
print_todo_list(todos)
|
|
253
|
+
|
|
254
|
+
# Create directory
|
|
255
|
+
repo_dir = os.path.join(os.getcwd(), 'repo')
|
|
256
|
+
os.makedirs(repo_dir, exist_ok=True)
|
|
257
|
+
|
|
258
|
+
# Clone repository
|
|
259
|
+
print("Cloning repository...")
|
|
260
|
+
success, _ = run_command(f"git clone {repo_url} .", cwd=repo_dir)
|
|
261
|
+
if not success:
|
|
262
|
+
print("Failed to clone repository")
|
|
263
|
+
print("Trying again with --depth 1...")
|
|
264
|
+
success, _ = run_command(f"git clone --depth 1 {repo_url} .", cwd=repo_dir)
|
|
265
|
+
if not success:
|
|
266
|
+
print("Failed to clone repository even with --depth 1")
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
todos = update_todo(todos, 0, "completed")
|
|
270
|
+
todos = update_todo(todos, 1, "in_progress")
|
|
271
|
+
print_todo_list(todos)
|
|
272
|
+
|
|
273
|
+
# Step 2: Examine repository structure
|
|
274
|
+
print("Analyzing repository structure...")
|
|
275
|
+
|
|
276
|
+
# Python project checks
|
|
277
|
+
has_requirements = os.path.exists(os.path.join(repo_dir, 'requirements.txt'))
|
|
278
|
+
has_setup_py = os.path.exists(os.path.join(repo_dir, 'setup.py'))
|
|
279
|
+
has_pyproject = os.path.exists(os.path.join(repo_dir, 'pyproject.toml'))
|
|
280
|
+
|
|
281
|
+
# JavaScript project checks
|
|
282
|
+
has_package_json = os.path.exists(os.path.join(repo_dir, 'package.json'))
|
|
283
|
+
|
|
284
|
+
# Print repository info
|
|
285
|
+
print("Repository information:")
|
|
286
|
+
print(f" Python project: {has_requirements or has_setup_py or has_pyproject}")
|
|
287
|
+
print(f" JavaScript project: {has_package_json}")
|
|
288
|
+
|
|
289
|
+
todos = update_todo(todos, 1, "completed")
|
|
290
|
+
todos = update_todo(todos, 2, "in_progress")
|
|
291
|
+
print_todo_list(todos)
|
|
292
|
+
|
|
293
|
+
# Step 3: Setup Python environment if needed
|
|
294
|
+
if has_requirements or has_setup_py or has_pyproject:
|
|
295
|
+
print("Setting up Python environment...")
|
|
296
|
+
|
|
297
|
+
# Create and activate virtual environment
|
|
298
|
+
run_command('python -m venv .venv', cwd=repo_dir)
|
|
299
|
+
|
|
300
|
+
# Install dependencies
|
|
301
|
+
if has_requirements:
|
|
302
|
+
print("Installing requirements.txt dependencies...")
|
|
303
|
+
run_command('.venv/bin/pip install -r requirements.txt', cwd=repo_dir)
|
|
304
|
+
|
|
305
|
+
if has_setup_py:
|
|
306
|
+
print("Installing package in development mode...")
|
|
307
|
+
run_command('.venv/bin/pip install -e .', cwd=repo_dir)
|
|
308
|
+
|
|
309
|
+
# Setup JavaScript environment if needed
|
|
310
|
+
if has_package_json:
|
|
311
|
+
print("Setting up JavaScript environment...")
|
|
312
|
+
run_command('npm install', cwd=repo_dir)
|
|
313
|
+
|
|
314
|
+
todos = update_todo(todos, 2, "completed")
|
|
315
|
+
todos = update_todo(todos, 3, "in_progress")
|
|
316
|
+
print_todo_list(todos)
|
|
317
|
+
|
|
318
|
+
# Step 4: Run tests if available
|
|
319
|
+
if has_requirements or has_setup_py or has_pyproject:
|
|
320
|
+
if os.path.exists(os.path.join(repo_dir, 'tests')):
|
|
321
|
+
print("Running tests...")
|
|
322
|
+
run_command('.venv/bin/pytest', cwd=repo_dir)
|
|
323
|
+
|
|
324
|
+
todos = update_todo(todos, 3, "completed")
|
|
325
|
+
todos = update_todo(todos, 4, "in_progress")
|
|
326
|
+
print_todo_list(todos)
|
|
327
|
+
|
|
328
|
+
# Step 5: Print successful commands
|
|
329
|
+
print("\\n============================================================")
|
|
330
|
+
print("ā
Successful commands:")
|
|
331
|
+
print("git clone " + repo_url)
|
|
332
|
+
if has_requirements:
|
|
333
|
+
print("python -m venv .venv")
|
|
334
|
+
print(".venv/bin/pip install -r requirements.txt")
|
|
335
|
+
if has_setup_py:
|
|
336
|
+
print(".venv/bin/pip install -e .")
|
|
337
|
+
if has_package_json:
|
|
338
|
+
print("npm install")
|
|
339
|
+
print("============================================================")
|
|
340
|
+
|
|
341
|
+
todos = update_todo(todos, 4, "completed")
|
|
342
|
+
print_todo_list(todos)
|
|
343
|
+
|
|
344
|
+
print("Repository setup complete!")
|
|
345
|
+
return True
|
|
346
|
+
|
|
347
|
+
if __name__ == '__main__':
|
|
348
|
+
if len(sys.argv) < 2:
|
|
349
|
+
print('Usage: python simple_agent.py <repository_url>')
|
|
350
|
+
sys.exit(1)
|
|
351
|
+
|
|
352
|
+
repo_url = sys.argv[1]
|
|
353
|
+
print('GitArsenal Simple Agent')
|
|
354
|
+
print('Repository URL: ' + repo_url)
|
|
355
|
+
print('Working Directory: ' + os.getcwd())
|
|
356
|
+
|
|
357
|
+
start_time = time.time()
|
|
358
|
+
success = setup_repository(repo_url)
|
|
359
|
+
end_time = time.time()
|
|
360
|
+
|
|
361
|
+
print('Setup completed in ' + str(round(end_time - start_time, 2)) + ' seconds')
|
|
362
|
+
|
|
363
|
+
if success:
|
|
364
|
+
print('Repository setup successful!')
|
|
365
|
+
print('You can now work with the repository in the repo directory')
|
|
366
|
+
else:
|
|
367
|
+
print('Repository setup failed')
|
|
368
|
+
sys.exit(1)
|
|
369
|
+
"""
|
|
370
|
+
|
|
371
|
+
# Debugging: Check if we can write to the directory
|
|
372
|
+
try:
|
|
373
|
+
# First check if we can list the directory
|
|
374
|
+
result = sandbox.commands.run("ls -la /home/user")
|
|
375
|
+
print(f"Directory contents of /home/user: {result.stdout}")
|
|
376
|
+
|
|
377
|
+
# Check if we can create a simple file
|
|
378
|
+
result = sandbox.commands.run("echo 'test' > /home/user/test.txt")
|
|
379
|
+
print(f"Create test file result: {result.exit_code}")
|
|
380
|
+
|
|
381
|
+
# Check if the file was created
|
|
382
|
+
result = sandbox.commands.run("cat /home/user/test.txt")
|
|
383
|
+
print(f"Test file contents: {result.stdout}")
|
|
384
|
+
except Exception as e:
|
|
385
|
+
print(f"ā ļø Directory check failed: {e}")
|
|
386
|
+
|
|
387
|
+
# Method 1: Use Python to write the file
|
|
388
|
+
try:
|
|
389
|
+
# Use Python to create the file
|
|
390
|
+
python_code = f'''
|
|
391
|
+
import os
|
|
392
|
+
|
|
393
|
+
script_content = """{script_content}"""
|
|
394
|
+
|
|
395
|
+
with open("/home/user/simple_agent.py", "w") as f:
|
|
396
|
+
f.write(script_content)
|
|
397
|
+
|
|
398
|
+
print("File written successfully")
|
|
399
|
+
'''
|
|
400
|
+
|
|
401
|
+
result = sandbox.run_code(python_code)
|
|
402
|
+
print(f"Python file creation result: {result}")
|
|
403
|
+
|
|
404
|
+
# Verify the file exists
|
|
405
|
+
result = sandbox.commands.run("ls -la /home/user/simple_agent.py")
|
|
406
|
+
if result.exit_code == 0:
|
|
407
|
+
print("ā
Simple agent script created successfully")
|
|
408
|
+
return True
|
|
409
|
+
else:
|
|
410
|
+
print(f"ā ļø File creation verification failed: {result.stderr}")
|
|
411
|
+
except Exception as e:
|
|
412
|
+
print(f"ā ļø Error creating file with Python: {e}")
|
|
413
|
+
|
|
414
|
+
# Method 2: Use a temporary file
|
|
415
|
+
try:
|
|
416
|
+
print("Trying with temporary file...")
|
|
417
|
+
# Create a temporary file
|
|
418
|
+
result = sandbox.commands.run("touch /home/user/temp_script.py")
|
|
419
|
+
|
|
420
|
+
# Write the script content to the temporary file in chunks
|
|
421
|
+
chunk_size = 1000 # Write in chunks to avoid command line limits
|
|
422
|
+
for i in range(0, len(script_content), chunk_size):
|
|
423
|
+
chunk = script_content[i:i+chunk_size]
|
|
424
|
+
# Escape special characters
|
|
425
|
+
chunk = chunk.replace('"', '\\"').replace("'", "\\'").replace("`", "\\`").replace("$", "\\$")
|
|
426
|
+
result = sandbox.commands.run(f'echo "{chunk}" >> /home/user/temp_script.py')
|
|
427
|
+
print(f" Writing chunk {i//chunk_size + 1}...")
|
|
428
|
+
|
|
429
|
+
# Move the temporary file to the final location
|
|
430
|
+
result = sandbox.commands.run("mv /home/user/temp_script.py /home/user/simple_agent.py")
|
|
431
|
+
|
|
432
|
+
# Make it executable
|
|
433
|
+
result = sandbox.commands.run("chmod +x /home/user/simple_agent.py")
|
|
434
|
+
|
|
435
|
+
# Verify the file exists
|
|
436
|
+
result = sandbox.commands.run("ls -la /home/user/simple_agent.py")
|
|
437
|
+
if result.exit_code == 0:
|
|
438
|
+
print("ā
Simple agent script created (chunked method)")
|
|
439
|
+
return True
|
|
440
|
+
else:
|
|
441
|
+
print(f"ā ļø File creation verification failed: {result.stderr}")
|
|
442
|
+
except Exception as e:
|
|
443
|
+
print(f"ā Failed to create simple_agent.py with chunked method: {e}")
|
|
444
|
+
|
|
445
|
+
# Method 3: Use a heredoc approach
|
|
446
|
+
try:
|
|
447
|
+
print("Trying with heredoc approach...")
|
|
448
|
+
|
|
449
|
+
# Create a small script that uses heredoc to create the file
|
|
450
|
+
heredoc_script = """
|
|
451
|
+
cat > /home/user/simple_agent.py << 'EOL'
|
|
452
|
+
""" + script_content + """
|
|
453
|
+
EOL
|
|
454
|
+
"""
|
|
455
|
+
|
|
456
|
+
# Write the heredoc script to a temporary file
|
|
457
|
+
result = sandbox.commands.run("touch /home/user/create_script.sh")
|
|
458
|
+
result = sandbox.commands.run(f'echo "{heredoc_script}" > /home/user/create_script.sh')
|
|
459
|
+
|
|
460
|
+
# Make it executable
|
|
461
|
+
result = sandbox.commands.run("chmod +x /home/user/create_script.sh")
|
|
462
|
+
|
|
463
|
+
# Run the script
|
|
464
|
+
result = sandbox.commands.run("bash /home/user/create_script.sh")
|
|
465
|
+
|
|
466
|
+
# Verify the file exists
|
|
467
|
+
result = sandbox.commands.run("ls -la /home/user/simple_agent.py")
|
|
468
|
+
if result.exit_code == 0:
|
|
469
|
+
print("ā
Simple agent script created (heredoc method)")
|
|
470
|
+
return True
|
|
471
|
+
else:
|
|
472
|
+
print(f"ā ļø File creation verification failed: {result.stderr}")
|
|
473
|
+
except Exception as e:
|
|
474
|
+
print(f"ā Failed to create simple_agent.py with heredoc method: {e}")
|
|
475
|
+
|
|
476
|
+
print("ā All methods to create simple_agent.py failed")
|
|
477
|
+
return False
|
|
478
|
+
|
|
479
|
+
def run_e2b_sandbox(repo_url, setup_commands=None, api_keys=None):
|
|
480
|
+
"""
|
|
481
|
+
Run the E2B sandbox with the given repository URL
|
|
482
|
+
"""
|
|
483
|
+
print("š Creating E2B sandbox...")
|
|
484
|
+
try:
|
|
485
|
+
# Create a new E2B sandbox with a longer timeout (30 minutes)
|
|
486
|
+
sandbox = Sandbox.create(timeout=1800)
|
|
487
|
+
print("ā
E2B sandbox created successfully (30 minute timeout)")
|
|
488
|
+
|
|
489
|
+
# Install required packages
|
|
490
|
+
print("š¦ Installing required packages in sandbox...")
|
|
491
|
+
install_dependencies_in_sandbox(sandbox)
|
|
492
|
+
|
|
493
|
+
# Upload claude_code_agent.py and related files
|
|
494
|
+
upload_claude_agent_to_sandbox(sandbox)
|
|
495
|
+
print("š¦ Installing required packages for claude_code_agent...")
|
|
496
|
+
result = sandbox.commands.run("cd /home/user/kill_claude && pip install -r requirements.txt")
|
|
497
|
+
if result.exit_code != 0:
|
|
498
|
+
print(f"ā ļø Failed to install requirements for claude_code_agent: {result.stderr}")
|
|
499
|
+
else:
|
|
500
|
+
print("ā
Successfully installed requirements for claude_code_agent")
|
|
501
|
+
|
|
502
|
+
# Verify package installation
|
|
503
|
+
result = sandbox.commands.run("pip list | grep -E 'anthropic|typer|rich'")
|
|
504
|
+
print(f"Installed packages verification: {result.stdout}")
|
|
505
|
+
|
|
506
|
+
# Create a wrapper script to run claude_code_agent.py
|
|
507
|
+
wrapper_script = """#!/usr/bin/env python3
|
|
508
|
+
import sys
|
|
509
|
+
import os
|
|
510
|
+
import subprocess
|
|
511
|
+
|
|
512
|
+
if __name__ == "__main__":
|
|
513
|
+
if len(sys.argv) < 2:
|
|
514
|
+
print("Usage: python run_claude_agent.py <prompt>")
|
|
515
|
+
sys.exit(1)
|
|
516
|
+
|
|
517
|
+
prompt = sys.argv[1]
|
|
518
|
+
|
|
519
|
+
# Set up the environment
|
|
520
|
+
os.environ['ANTHROPIC_API_KEY'] = os.environ.get('ANTHROPIC_API_KEY', '')
|
|
521
|
+
|
|
522
|
+
try:
|
|
523
|
+
# Import the module
|
|
524
|
+
sys.path.append('/home/user')
|
|
525
|
+
from kill_claude import claude_code_agent
|
|
526
|
+
|
|
527
|
+
# Set sys.argv to use the query subcommand
|
|
528
|
+
sys.argv = ['/home/user/kill_claude/claude_code_agent.py', 'query', prompt]
|
|
529
|
+
|
|
530
|
+
# Call the main function
|
|
531
|
+
claude_code_agent.main()
|
|
532
|
+
except Exception as e:
|
|
533
|
+
print(f"Error executing claude_code_agent.py: {e}")
|
|
534
|
+
import traceback
|
|
535
|
+
traceback.print_exc()
|
|
536
|
+
sys.exit(1)
|
|
537
|
+
"""
|
|
538
|
+
|
|
539
|
+
sandbox.run_code(f"""
|
|
540
|
+
with open('/home/user/run_claude_agent.py', 'w') as f:
|
|
541
|
+
f.write({repr(wrapper_script)})
|
|
542
|
+
print("ā
Created wrapper script for claude_code_agent.py")
|
|
543
|
+
""")
|
|
544
|
+
|
|
545
|
+
# List the contents of the kill_claude directory
|
|
546
|
+
print("š Listing contents of kill_claude directory:")
|
|
547
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude")
|
|
548
|
+
print(result.stdout)
|
|
549
|
+
|
|
550
|
+
# List the contents of the tools directory
|
|
551
|
+
print("š Listing contents of kill_claude/tools directory:")
|
|
552
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/tools")
|
|
553
|
+
print(result.stdout)
|
|
554
|
+
|
|
555
|
+
# List the contents of the prompts directory
|
|
556
|
+
print("š Listing contents of kill_claude/prompts directory:")
|
|
557
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/prompts")
|
|
558
|
+
print(result.stdout)
|
|
559
|
+
|
|
560
|
+
# Find the Python executable path
|
|
561
|
+
result = sandbox.commands.run("which python")
|
|
562
|
+
python_path = result.stdout.strip()
|
|
563
|
+
print(f"Python executable path: {python_path}")
|
|
564
|
+
|
|
565
|
+
# Test Python interpreter
|
|
566
|
+
result = sandbox.commands.run("python -c \"print('Python interpreter test')\"")
|
|
567
|
+
if result.exit_code == 0:
|
|
568
|
+
print("ā
Python interpreter is working correctly")
|
|
569
|
+
else:
|
|
570
|
+
print("ā Python interpreter test failed")
|
|
571
|
+
print(f"Error: {result.stderr}")
|
|
572
|
+
|
|
573
|
+
# Set up API keys in the sandbox environment
|
|
574
|
+
if api_keys:
|
|
575
|
+
for key_name, key_value in api_keys.items():
|
|
576
|
+
if key_value:
|
|
577
|
+
# Set environment variable in the sandbox
|
|
578
|
+
sandbox.run_code(f"""
|
|
579
|
+
import os
|
|
580
|
+
os.environ['{key_name}'] = '{key_value}'
|
|
581
|
+
print(f"ā
Set {key_name} in sandbox environment")
|
|
582
|
+
""")
|
|
583
|
+
|
|
584
|
+
print("\n" + "="*80)
|
|
585
|
+
print("š¤ CLAUDE AGENT REPOSITORY SETUP")
|
|
586
|
+
print("="*80)
|
|
587
|
+
print(f"Repository: {repo_url}")
|
|
588
|
+
print(f"Working Directory: /home/user")
|
|
589
|
+
print(f"Available Credentials: {len(api_keys) if api_keys else 0} items")
|
|
590
|
+
print("="*80 + "\n")
|
|
591
|
+
|
|
592
|
+
print("\n" + "="*60)
|
|
593
|
+
print("š AGENT OUTPUT (LIVE)")
|
|
594
|
+
print("="*60)
|
|
595
|
+
|
|
596
|
+
# Create a prompt for the agent
|
|
597
|
+
claude_prompt = f"clone, setup and run {repo_url}. At the end of the setup process, print the ordered list of every shell command that actually ran successfully (exclude any commands that returned non-zero exit codes). Show each command exactly as executed, one per line."
|
|
598
|
+
|
|
599
|
+
# Set environment variables directly in the command
|
|
600
|
+
print("š Running claude_code_agent.py...")
|
|
601
|
+
if api_keys and 'ANTHROPIC_API_KEY' in api_keys:
|
|
602
|
+
anthropic_key = api_keys['ANTHROPIC_API_KEY']
|
|
603
|
+
# Print the first few characters of the API key to verify it's being passed correctly
|
|
604
|
+
print(f"ā
Using Anthropic API key: {anthropic_key[:8]}...")
|
|
605
|
+
|
|
606
|
+
# Run the claude_code_agent.py directly with the environment variable
|
|
607
|
+
print("š Running claude_code_agent.py directly...")
|
|
608
|
+
|
|
609
|
+
# Debug: Check if the file exists and is executable
|
|
610
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
|
|
611
|
+
print(f"File check: {result.stdout}")
|
|
612
|
+
|
|
613
|
+
# Test importing the module
|
|
614
|
+
import_test = sandbox.run_code("""
|
|
615
|
+
try:
|
|
616
|
+
import sys
|
|
617
|
+
sys.path.append('/home/user')
|
|
618
|
+
from kill_claude import claude_code_agent
|
|
619
|
+
print("ā
Successfully imported claude_code_agent module")
|
|
620
|
+
|
|
621
|
+
# Check if the main function exists and is callable
|
|
622
|
+
if hasattr(claude_code_agent, 'main'):
|
|
623
|
+
print("ā
main function exists in claude_code_agent module")
|
|
624
|
+
if callable(getattr(claude_code_agent, 'main')):
|
|
625
|
+
print("ā
main function is callable")
|
|
626
|
+
else:
|
|
627
|
+
print("ā main function is not callable")
|
|
628
|
+
else:
|
|
629
|
+
print("ā main function does not exist in claude_code_agent module")
|
|
630
|
+
|
|
631
|
+
# Check if it's a Typer app
|
|
632
|
+
if hasattr(claude_code_agent, 'app') and hasattr(claude_code_agent.app, 'command'):
|
|
633
|
+
print("ā
This is a Typer app")
|
|
634
|
+
print("Available commands:", [cmd.name for cmd in claude_code_agent.app.registered_commands])
|
|
635
|
+
else:
|
|
636
|
+
print("ā This is not a Typer app or app structure is different")
|
|
637
|
+
|
|
638
|
+
# Print the module's attributes to see what's available
|
|
639
|
+
print("Module attributes:", dir(claude_code_agent))
|
|
640
|
+
except Exception as e:
|
|
641
|
+
print(f"ā Failed to import claude_code_agent module: {e}")
|
|
642
|
+
""")
|
|
643
|
+
|
|
644
|
+
# Now run the actual command with more debugging
|
|
645
|
+
print("š Running claude_code_agent.py with debugging...")
|
|
646
|
+
|
|
647
|
+
# Try with a simpler approach - just the query subcommand
|
|
648
|
+
debug_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
|
|
649
|
+
print("Command to execute:", debug_cmd)
|
|
650
|
+
|
|
651
|
+
# Define stdout and stderr handlers to stream output in real-time
|
|
652
|
+
def on_stdout(data):
|
|
653
|
+
print(data.strip())
|
|
654
|
+
|
|
655
|
+
def on_stderr(data):
|
|
656
|
+
print(f"STDERR: {data.strip()}")
|
|
657
|
+
|
|
658
|
+
# Run the command with streaming output
|
|
659
|
+
print("Starting command execution with streaming output...")
|
|
660
|
+
try:
|
|
661
|
+
result = sandbox.commands.run(debug_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
662
|
+
|
|
663
|
+
print(f"Claude agent exit code: {result.exit_code}")
|
|
664
|
+
|
|
665
|
+
if result.exit_code != 0:
|
|
666
|
+
print(f"ā ļø Claude agent failed with exit code {result.exit_code}")
|
|
667
|
+
|
|
668
|
+
# Try to diagnose the issue
|
|
669
|
+
print("š Diagnosing the issue...")
|
|
670
|
+
|
|
671
|
+
# Check if the file exists
|
|
672
|
+
file_check = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
|
|
673
|
+
print(f"File exists: {file_check.exit_code == 0}")
|
|
674
|
+
|
|
675
|
+
# Check Python version
|
|
676
|
+
python_version = sandbox.commands.run("python --version")
|
|
677
|
+
print(f"Python version: {python_version.stdout}")
|
|
678
|
+
else:
|
|
679
|
+
print("ā
Claude agent completed successfully")
|
|
680
|
+
return True
|
|
681
|
+
|
|
682
|
+
# Use the simple agent as a fallback
|
|
683
|
+
print("Will use simple agent as a fallback if needed...")
|
|
684
|
+
|
|
685
|
+
# Try using the wrapper script
|
|
686
|
+
print("Trying wrapper script execution method...")
|
|
687
|
+
wrapper_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python run_claude_agent.py \"{claude_prompt}\""
|
|
688
|
+
wrapper_result = sandbox.commands.run(wrapper_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
689
|
+
print(f"Wrapper script execution result: {wrapper_result.exit_code}")
|
|
690
|
+
|
|
691
|
+
if wrapper_result.exit_code == 0:
|
|
692
|
+
print("ā
Claude agent completed successfully using wrapper script")
|
|
693
|
+
return True
|
|
694
|
+
|
|
695
|
+
# Try direct command with query
|
|
696
|
+
print("Trying direct command with query subcommand...")
|
|
697
|
+
direct_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
|
|
698
|
+
direct_result = sandbox.commands.run(direct_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
699
|
+
print(f"Direct command result: {direct_result.exit_code}")
|
|
700
|
+
|
|
701
|
+
if direct_result.exit_code == 0:
|
|
702
|
+
print("ā
Claude agent completed successfully using direct command")
|
|
703
|
+
return True
|
|
704
|
+
|
|
705
|
+
# Final fallback: Create and use a simple agent
|
|
706
|
+
print("š Falling back to simple agent...")
|
|
707
|
+
if create_simple_agent_script(sandbox):
|
|
708
|
+
simple_cmd = f"cd /home/user && python simple_agent.py \"{repo_url}\""
|
|
709
|
+
simple_result = sandbox.commands.run(simple_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
710
|
+
print(f"Simple agent result: {simple_result.exit_code}")
|
|
711
|
+
|
|
712
|
+
if simple_result.exit_code == 0:
|
|
713
|
+
print("ā
Simplified claude agent completed successfully")
|
|
714
|
+
return True
|
|
715
|
+
return False
|
|
716
|
+
|
|
717
|
+
except KeyboardInterrupt:
|
|
718
|
+
print("\nš Execution interrupted by user")
|
|
719
|
+
# Try to gracefully terminate the process
|
|
720
|
+
try:
|
|
721
|
+
sandbox.commands.run("pkill -f 'python.*claude_code_agent.py'", timeout=10)
|
|
722
|
+
except:
|
|
723
|
+
pass
|
|
724
|
+
return False
|
|
725
|
+
else:
|
|
726
|
+
print("ā ļø No Anthropic API key found")
|
|
727
|
+
return False
|
|
728
|
+
except KeyboardInterrupt:
|
|
729
|
+
print("\nš Execution interrupted by user")
|
|
730
|
+
return False
|
|
731
|
+
except Exception as e:
|
|
732
|
+
print(f"ā E2B sandbox setup failed: {e}")
|
|
733
|
+
return False
|
|
734
|
+
|
|
735
|
+
def main():
|
|
736
|
+
"""
|
|
737
|
+
Main function to run the E2B sandbox
|
|
738
|
+
"""
|
|
739
|
+
parser = argparse.ArgumentParser(description="Run an E2B sandbox with a repository")
|
|
740
|
+
parser.add_argument("--repo", required=True, help="Repository URL to clone")
|
|
741
|
+
parser.add_argument("--setup-commands", help="JSON file with setup commands")
|
|
742
|
+
parser.add_argument("--openai-api-key", help="OpenAI API key")
|
|
743
|
+
parser.add_argument("--anthropic-api-key", help="Anthropic API key")
|
|
744
|
+
args = parser.parse_args()
|
|
745
|
+
|
|
746
|
+
# Prepare API keys
|
|
747
|
+
api_keys = {}
|
|
748
|
+
|
|
749
|
+
# Check for OpenAI API key
|
|
750
|
+
openai_api_key = args.openai_api_key or os.environ.get("OPENAI_API_KEY")
|
|
751
|
+
if openai_api_key:
|
|
752
|
+
api_keys["OPENAI_API_KEY"] = openai_api_key
|
|
753
|
+
|
|
754
|
+
# Check for Anthropic API key
|
|
755
|
+
anthropic_api_key = args.anthropic_api_key or os.environ.get("ANTHROPIC_API_KEY")
|
|
756
|
+
if anthropic_api_key:
|
|
757
|
+
api_keys["ANTHROPIC_API_KEY"] = anthropic_api_key
|
|
758
|
+
else:
|
|
759
|
+
# Try to get Anthropic API key from modal_tokens.json
|
|
760
|
+
modal_tokens_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "modal_tokens.json")
|
|
761
|
+
if os.path.exists(modal_tokens_path):
|
|
762
|
+
try:
|
|
763
|
+
with open(modal_tokens_path, "r") as f:
|
|
764
|
+
modal_tokens = json.load(f)
|
|
765
|
+
if "anthropic_api_key" in modal_tokens:
|
|
766
|
+
api_keys["ANTHROPIC_API_KEY"] = modal_tokens["anthropic_api_key"]
|
|
767
|
+
print("ā
Found Anthropic API key in modal_tokens.json")
|
|
768
|
+
except Exception as e:
|
|
769
|
+
print(f"Error loading modal_tokens.json: {e}")
|
|
770
|
+
|
|
771
|
+
# Parse setup commands if provided
|
|
772
|
+
setup_commands = None
|
|
773
|
+
if args.setup_commands:
|
|
774
|
+
try:
|
|
775
|
+
with open(args.setup_commands, "r") as f:
|
|
776
|
+
setup_commands = json.load(f)
|
|
777
|
+
except Exception as e:
|
|
778
|
+
print(f"Error loading setup commands: {e}")
|
|
779
|
+
|
|
780
|
+
# Run the sandbox
|
|
781
|
+
success = run_e2b_sandbox(args.repo, setup_commands, api_keys)
|
|
782
|
+
|
|
783
|
+
# Exit with appropriate code
|
|
784
|
+
sys.exit(0 if success else 1)
|
|
785
|
+
|
|
786
|
+
if __name__ == "__main__":
|
|
787
|
+
main()
|