gitarsenal-cli 1.9.97 โ 1.9.99
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/lib/e2b-sandbox.js +89 -1
- package/package.json +1 -1
- package/python/__pycache__/e2b_sandbox_agent.cpython-313.pyc +0 -0
- package/python/__pycache__/fetch_modal_tokens.cpython-312.pyc +0 -0
- package/python/__pycache__/fetch_modal_tokens.cpython-313.pyc +0 -0
- package/python/e2b_sandbox_agent.py +243 -183
- package/python/fetch_modal_tokens.py +19 -11
- package/python/test_modalSandboxScript.py +12 -3
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-09-
|
|
1
|
+
{"created":"2025-09-14T10:44:37.356Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/lib/e2b-sandbox.js
CHANGED
|
@@ -41,6 +41,40 @@ function getPythonExecutable() {
|
|
|
41
41
|
return isWindows ? 'python' : 'python3';
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Fetch E2B API key directly from the server
|
|
46
|
+
* @returns {Promise<string>} - The E2B API key
|
|
47
|
+
*/
|
|
48
|
+
async function fetchE2BApiKey() {
|
|
49
|
+
try {
|
|
50
|
+
console.log(chalk.blue('๐ Fetching E2B API key directly from server...'));
|
|
51
|
+
|
|
52
|
+
const pythonExecutable = getPythonExecutable();
|
|
53
|
+
const fetchTokensScript = path.join(__dirname, '..', 'python', 'fetch_modal_tokens.py');
|
|
54
|
+
|
|
55
|
+
// Run the fetch_modal_tokens.py script with --output-e2b-key flag
|
|
56
|
+
const { stdout, stderr } = await execAsync(`${pythonExecutable} ${fetchTokensScript} --output-e2b-key`, {
|
|
57
|
+
env: { ...process.env },
|
|
58
|
+
timeout: 30000 // 30 seconds timeout
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Parse the output to find the E2B API key
|
|
62
|
+
const e2bKeyMatch = stdout.match(/E2B_API_KEY=(e2b_[a-zA-Z0-9]+)/);
|
|
63
|
+
if (e2bKeyMatch && e2bKeyMatch[1]) {
|
|
64
|
+
const e2bApiKey = e2bKeyMatch[1];
|
|
65
|
+
console.log(chalk.green(`โ
Successfully fetched E2B API key from server (format: ${e2bApiKey.substring(0, 5)}...)`));
|
|
66
|
+
return e2bApiKey;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.error(chalk.yellow('โ ๏ธ Could not extract E2B API key from fetch_modal_tokens.py output'));
|
|
70
|
+
console.error(chalk.gray('Output: ' + stdout.substring(0, 100) + '...'));
|
|
71
|
+
return null;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(chalk.red(`โ Error fetching E2B API key: ${error.message}`));
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
44
78
|
/**
|
|
45
79
|
* Run an E2B sandbox with the given options
|
|
46
80
|
* @param {Object} options - Sandbox options
|
|
@@ -63,10 +97,27 @@ async function runE2BSandbox(options) {
|
|
|
63
97
|
// Check if E2B_API_KEY is already set in environment variables
|
|
64
98
|
let e2bApiKey = process.env.E2B_API_KEY;
|
|
65
99
|
|
|
100
|
+
// Check if the key is a placeholder value
|
|
101
|
+
if (e2bApiKey && (e2bApiKey === 'your_e2b_api_key' || e2bApiKey.startsWith('placeholder'))) {
|
|
102
|
+
console.log(chalk.yellow('โ ๏ธ Found placeholder E2B API key in environment, will try to get real key'));
|
|
103
|
+
e2bApiKey = null;
|
|
104
|
+
}
|
|
105
|
+
|
|
66
106
|
// If not, try to get it from apiKeys
|
|
67
107
|
if (!e2bApiKey && apiKeys.E2B_API_KEY) {
|
|
68
108
|
e2bApiKey = apiKeys.E2B_API_KEY;
|
|
69
|
-
|
|
109
|
+
// Check if the key from apiKeys is a placeholder
|
|
110
|
+
if (e2bApiKey === 'your_e2b_api_key' || e2bApiKey.startsWith('placeholder')) {
|
|
111
|
+
console.log(chalk.yellow('โ ๏ธ Found placeholder E2B API key in apiKeys, will try to get real key'));
|
|
112
|
+
e2bApiKey = null;
|
|
113
|
+
} else {
|
|
114
|
+
console.log(chalk.green('โ
Using E2B API key from apiKeys'));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// If still not found, try to fetch it directly from the server
|
|
119
|
+
if (!e2bApiKey) {
|
|
120
|
+
e2bApiKey = await fetchE2BApiKey();
|
|
70
121
|
}
|
|
71
122
|
|
|
72
123
|
// If still not found, try to get it from modal_tokens.json
|
|
@@ -133,8 +184,29 @@ async function runE2BSandbox(options) {
|
|
|
133
184
|
}
|
|
134
185
|
});
|
|
135
186
|
|
|
187
|
+
// Clean up function to remove the E2B API key
|
|
188
|
+
const cleanupE2BApiKey = () => {
|
|
189
|
+
try {
|
|
190
|
+
// Remove the E2B API key from modal_tokens.json if it exists
|
|
191
|
+
const modalTokensPath = path.join(__dirname, '..', 'python', 'modal_tokens.json');
|
|
192
|
+
if (fs.existsSync(modalTokensPath)) {
|
|
193
|
+
const modalTokens = JSON.parse(fs.readFileSync(modalTokensPath, 'utf8'));
|
|
194
|
+
if (modalTokens.e2b_api_key) {
|
|
195
|
+
delete modalTokens.e2b_api_key;
|
|
196
|
+
fs.writeFileSync(modalTokensPath, JSON.stringify(modalTokens, null, 2));
|
|
197
|
+
console.log(chalk.green('๐งน Removed E2B API key from modal_tokens.json'));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(chalk.yellow(`โ ๏ธ Error cleaning up E2B API key: ${error.message}`));
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
136
205
|
return new Promise((resolve, reject) => {
|
|
137
206
|
pythonProcess.on('close', (code) => {
|
|
207
|
+
// Clean up the E2B API key
|
|
208
|
+
cleanupE2BApiKey();
|
|
209
|
+
|
|
138
210
|
if (code === 0 || code === 130) { // 130 is the exit code for SIGINT (Ctrl+C)
|
|
139
211
|
console.log(chalk.green('โ
E2B sandbox session completed'));
|
|
140
212
|
resolve({ success: true });
|
|
@@ -146,10 +218,26 @@ async function runE2BSandbox(options) {
|
|
|
146
218
|
});
|
|
147
219
|
|
|
148
220
|
pythonProcess.on('error', (error) => {
|
|
221
|
+
// Clean up the E2B API key
|
|
222
|
+
cleanupE2BApiKey();
|
|
223
|
+
|
|
149
224
|
console.error(chalk.red(`โ E2B sandbox session failed`));
|
|
150
225
|
console.error(chalk.red(` Error: ${error.message}`));
|
|
151
226
|
reject(error);
|
|
152
227
|
});
|
|
228
|
+
|
|
229
|
+
// Handle process termination signals
|
|
230
|
+
const handleTermination = () => {
|
|
231
|
+
if (pythonProcess && !pythonProcess.killed) {
|
|
232
|
+
pythonProcess.kill('SIGINT');
|
|
233
|
+
}
|
|
234
|
+
cleanupE2BApiKey();
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Listen for termination signals
|
|
238
|
+
process.on('SIGINT', handleTermination);
|
|
239
|
+
process.on('SIGTERM', handleTermination);
|
|
240
|
+
process.on('exit', handleTermination);
|
|
153
241
|
});
|
|
154
242
|
}
|
|
155
243
|
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -482,29 +482,71 @@ def run_e2b_sandbox(repo_url, setup_commands=None, api_keys=None):
|
|
|
482
482
|
"""
|
|
483
483
|
print("๐ Creating E2B sandbox...")
|
|
484
484
|
try:
|
|
485
|
-
#
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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")
|
|
485
|
+
# Fetch the E2B API key directly from the server
|
|
486
|
+
try:
|
|
487
|
+
print("๐ Fetching E2B API key directly from server...")
|
|
488
|
+
from fetch_modal_tokens import fetch_default_tokens_from_gitarsenal
|
|
489
|
+
token_id, token_secret, e2b_api_key, openai_api_key, anthropic_api_key, openrouter_api_key, groq_api_key = fetch_default_tokens_from_gitarsenal()
|
|
501
490
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
491
|
+
if e2b_api_key and e2b_api_key != "your_e2b_api_key" and not e2b_api_key.startswith("placeholder"):
|
|
492
|
+
# Set it in the environment for the Sandbox.create() call
|
|
493
|
+
os.environ["E2B_API_KEY"] = e2b_api_key
|
|
494
|
+
else:
|
|
495
|
+
print("โ ๏ธ Could not get valid E2B API key from server")
|
|
496
|
+
e2b_api_key = None
|
|
497
|
+
except Exception as e:
|
|
498
|
+
print(f"โ ๏ธ Could not fetch E2B API key from server: {e}")
|
|
499
|
+
e2b_api_key = None
|
|
500
|
+
|
|
501
|
+
# If we couldn't fetch the key directly, check if it's in api_keys
|
|
502
|
+
if not e2b_api_key and api_keys and "E2B_API_KEY" in api_keys:
|
|
503
|
+
e2b_api_key = api_keys["E2B_API_KEY"]
|
|
504
|
+
# Check if the key from api_keys is a placeholder
|
|
505
|
+
if e2b_api_key == "your_e2b_api_key" or e2b_api_key.startswith("placeholder"):
|
|
506
|
+
print("โ ๏ธ Found placeholder E2B API key in api_keys")
|
|
507
|
+
e2b_api_key = None
|
|
508
|
+
else:
|
|
509
|
+
os.environ["E2B_API_KEY"] = e2b_api_key
|
|
510
|
+
print("โ
Using E2B API key from api_keys")
|
|
511
|
+
|
|
512
|
+
# Last resort: check environment
|
|
513
|
+
if not e2b_api_key:
|
|
514
|
+
e2b_api_key = os.environ.get("E2B_API_KEY")
|
|
515
|
+
# Check if the key is a placeholder value
|
|
516
|
+
if e2b_api_key and (e2b_api_key == "your_e2b_api_key" or e2b_api_key.startswith("placeholder")):
|
|
517
|
+
print("โ ๏ธ Found placeholder E2B API key in environment")
|
|
518
|
+
e2b_api_key = None
|
|
519
|
+
|
|
520
|
+
if not e2b_api_key:
|
|
521
|
+
print("โ E2B API key not found")
|
|
522
|
+
print("Please set the E2B_API_KEY environment variable or add it to your API keys")
|
|
523
|
+
return False
|
|
505
524
|
|
|
506
|
-
|
|
507
|
-
|
|
525
|
+
|
|
526
|
+
try:
|
|
527
|
+
# Create a new E2B sandbox with a longer timeout (30 minutes)
|
|
528
|
+
sandbox = Sandbox.create(timeout=1800)
|
|
529
|
+
print("โ
E2B sandbox created successfully (30 minute timeout)")
|
|
530
|
+
|
|
531
|
+
# Install required packages
|
|
532
|
+
print("๐ฆ Installing required packages in sandbox...")
|
|
533
|
+
install_dependencies_in_sandbox(sandbox)
|
|
534
|
+
|
|
535
|
+
# Upload claude_code_agent.py and related files
|
|
536
|
+
upload_claude_agent_to_sandbox(sandbox)
|
|
537
|
+
print("๐ฆ Installing required packages for claude_code_agent...")
|
|
538
|
+
result = sandbox.commands.run("cd /home/user/kill_claude && pip install -r requirements.txt")
|
|
539
|
+
if result.exit_code != 0:
|
|
540
|
+
print(f"โ ๏ธ Failed to install requirements for claude_code_agent: {result.stderr}")
|
|
541
|
+
else:
|
|
542
|
+
print("โ
Successfully installed requirements for claude_code_agent")
|
|
543
|
+
|
|
544
|
+
# Verify package installation
|
|
545
|
+
result = sandbox.commands.run("pip list | grep -E 'anthropic|typer|rich'")
|
|
546
|
+
print(f"Installed packages verification: {result.stdout}")
|
|
547
|
+
|
|
548
|
+
# Create a wrapper script to run claude_code_agent.py
|
|
549
|
+
wrapper_script = """#!/usr/bin/env python3
|
|
508
550
|
import sys
|
|
509
551
|
import os
|
|
510
552
|
import subprocess
|
|
@@ -535,83 +577,83 @@ if __name__ == "__main__":
|
|
|
535
577
|
traceback.print_exc()
|
|
536
578
|
sys.exit(1)
|
|
537
579
|
"""
|
|
538
|
-
|
|
539
|
-
|
|
580
|
+
|
|
581
|
+
sandbox.run_code(f"""
|
|
540
582
|
with open('/home/user/run_claude_agent.py', 'w') as f:
|
|
541
583
|
f.write({repr(wrapper_script)})
|
|
542
584
|
print("โ
Created wrapper script for claude_code_agent.py")
|
|
543
585
|
""")
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
586
|
+
|
|
587
|
+
# List the contents of the kill_claude directory
|
|
588
|
+
print("๐ Listing contents of kill_claude directory:")
|
|
589
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude")
|
|
590
|
+
print(result.stdout)
|
|
591
|
+
|
|
592
|
+
# List the contents of the tools directory
|
|
593
|
+
print("๐ Listing contents of kill_claude/tools directory:")
|
|
594
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/tools")
|
|
595
|
+
print(result.stdout)
|
|
596
|
+
|
|
597
|
+
# List the contents of the prompts directory
|
|
598
|
+
print("๐ Listing contents of kill_claude/prompts directory:")
|
|
599
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/prompts")
|
|
600
|
+
print(result.stdout)
|
|
601
|
+
|
|
602
|
+
# Find the Python executable path
|
|
603
|
+
result = sandbox.commands.run("which python")
|
|
604
|
+
python_path = result.stdout.strip()
|
|
605
|
+
print(f"Python executable path: {python_path}")
|
|
606
|
+
|
|
607
|
+
# Test Python interpreter
|
|
608
|
+
result = sandbox.commands.run("python -c \"print('Python interpreter test')\"")
|
|
609
|
+
if result.exit_code == 0:
|
|
610
|
+
print("โ
Python interpreter is working correctly")
|
|
611
|
+
else:
|
|
612
|
+
print("โ Python interpreter test failed")
|
|
613
|
+
print(f"Error: {result.stderr}")
|
|
614
|
+
|
|
615
|
+
# Set up API keys in the sandbox environment
|
|
616
|
+
if api_keys:
|
|
617
|
+
for key_name, key_value in api_keys.items():
|
|
618
|
+
if key_value:
|
|
619
|
+
# Set environment variable in the sandbox
|
|
620
|
+
sandbox.run_code(f"""
|
|
579
621
|
import os
|
|
580
622
|
os.environ['{key_name}'] = '{key_value}'
|
|
581
623
|
print(f"โ
Set {key_name} in sandbox environment")
|
|
582
624
|
""")
|
|
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
625
|
|
|
606
|
-
|
|
607
|
-
print("
|
|
626
|
+
print("\n" + "="*80)
|
|
627
|
+
print("๐ค CLAUDE AGENT REPOSITORY SETUP")
|
|
628
|
+
print("="*80)
|
|
629
|
+
print(f"Repository: {repo_url}")
|
|
630
|
+
print(f"Working Directory: /home/user")
|
|
631
|
+
print(f"Available Credentials: {len(api_keys) if api_keys else 0} items")
|
|
632
|
+
print("="*80 + "\n")
|
|
608
633
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
print(
|
|
634
|
+
print("\n" + "="*60)
|
|
635
|
+
print("๐ AGENT OUTPUT (LIVE)")
|
|
636
|
+
print("="*60)
|
|
612
637
|
|
|
613
|
-
#
|
|
614
|
-
|
|
638
|
+
# Create a prompt for the agent
|
|
639
|
+
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."
|
|
640
|
+
|
|
641
|
+
# Set environment variables directly in the command
|
|
642
|
+
print("๐ Running claude_code_agent.py...")
|
|
643
|
+
if api_keys and 'ANTHROPIC_API_KEY' in api_keys:
|
|
644
|
+
anthropic_key = api_keys['ANTHROPIC_API_KEY']
|
|
645
|
+
# Print the first few characters of the API key to verify it's being passed correctly
|
|
646
|
+
print(f"โ
Using Anthropic API key: {anthropic_key[:8]}...")
|
|
647
|
+
|
|
648
|
+
# Run the claude_code_agent.py directly with the environment variable
|
|
649
|
+
print("๐ Running claude_code_agent.py directly...")
|
|
650
|
+
|
|
651
|
+
# Debug: Check if the file exists and is executable
|
|
652
|
+
result = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
|
|
653
|
+
print(f"File check: {result.stdout}")
|
|
654
|
+
|
|
655
|
+
# Test importing the module
|
|
656
|
+
import_test = sandbox.run_code("""
|
|
615
657
|
try:
|
|
616
658
|
import sys
|
|
617
659
|
sys.path.append('/home/user')
|
|
@@ -640,97 +682,107 @@ try:
|
|
|
640
682
|
except Exception as e:
|
|
641
683
|
print(f"โ Failed to import claude_code_agent module: {e}")
|
|
642
684
|
""")
|
|
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
|
|
|
685
|
-
#
|
|
686
|
-
print("
|
|
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}")
|
|
686
|
+
# Now run the actual command with more debugging
|
|
687
|
+
print("๐ Running claude_code_agent.py with debugging...")
|
|
690
688
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
689
|
+
# Try with a simpler approach - just the query subcommand
|
|
690
|
+
debug_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
|
|
691
|
+
print("Command to execute:", debug_cmd)
|
|
694
692
|
|
|
695
|
-
#
|
|
696
|
-
|
|
697
|
-
|
|
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}")
|
|
693
|
+
# Define stdout and stderr handlers to stream output in real-time
|
|
694
|
+
def on_stdout(data):
|
|
695
|
+
print(data.strip())
|
|
700
696
|
|
|
701
|
-
|
|
702
|
-
print("
|
|
703
|
-
return True
|
|
697
|
+
def on_stderr(data):
|
|
698
|
+
print(f"STDERR: {data.strip()}")
|
|
704
699
|
|
|
705
|
-
#
|
|
706
|
-
print("
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
print(f"
|
|
700
|
+
# Run the command with streaming output
|
|
701
|
+
print("Starting command execution with streaming output...")
|
|
702
|
+
try:
|
|
703
|
+
result = sandbox.commands.run(debug_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
704
|
+
|
|
705
|
+
print(f"Claude agent exit code: {result.exit_code}")
|
|
711
706
|
|
|
712
|
-
if
|
|
713
|
-
print("
|
|
707
|
+
if result.exit_code != 0:
|
|
708
|
+
print(f"โ ๏ธ Claude agent failed with exit code {result.exit_code}")
|
|
709
|
+
|
|
710
|
+
# Try to diagnose the issue
|
|
711
|
+
print("๐ Diagnosing the issue...")
|
|
712
|
+
|
|
713
|
+
# Check if the file exists
|
|
714
|
+
file_check = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
|
|
715
|
+
print(f"File exists: {file_check.exit_code == 0}")
|
|
716
|
+
|
|
717
|
+
# Check Python version
|
|
718
|
+
python_version = sandbox.commands.run("python --version")
|
|
719
|
+
print(f"Python version: {python_version.stdout}")
|
|
720
|
+
else:
|
|
721
|
+
print("โ
Claude agent completed successfully")
|
|
714
722
|
return True
|
|
723
|
+
|
|
724
|
+
# Use the simple agent as a fallback
|
|
725
|
+
print("Will use simple agent as a fallback if needed...")
|
|
726
|
+
|
|
727
|
+
# Try using the wrapper script
|
|
728
|
+
print("Trying wrapper script execution method...")
|
|
729
|
+
wrapper_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python run_claude_agent.py \"{claude_prompt}\""
|
|
730
|
+
wrapper_result = sandbox.commands.run(wrapper_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
731
|
+
print(f"Wrapper script execution result: {wrapper_result.exit_code}")
|
|
732
|
+
|
|
733
|
+
if wrapper_result.exit_code == 0:
|
|
734
|
+
print("โ
Claude agent completed successfully using wrapper script")
|
|
735
|
+
return True
|
|
736
|
+
|
|
737
|
+
# Try direct command with query
|
|
738
|
+
print("Trying direct command with query subcommand...")
|
|
739
|
+
direct_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
|
|
740
|
+
direct_result = sandbox.commands.run(direct_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
741
|
+
print(f"Direct command result: {direct_result.exit_code}")
|
|
742
|
+
|
|
743
|
+
if direct_result.exit_code == 0:
|
|
744
|
+
print("โ
Claude agent completed successfully using direct command")
|
|
745
|
+
return True
|
|
746
|
+
|
|
747
|
+
# Final fallback: Create and use a simple agent
|
|
748
|
+
print("๐ Falling back to simple agent...")
|
|
749
|
+
if create_simple_agent_script(sandbox):
|
|
750
|
+
simple_cmd = f"cd /home/user && python simple_agent.py \"{repo_url}\""
|
|
751
|
+
simple_result = sandbox.commands.run(simple_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
|
|
752
|
+
print(f"Simple agent result: {simple_result.exit_code}")
|
|
753
|
+
|
|
754
|
+
if simple_result.exit_code == 0:
|
|
755
|
+
print("โ
Simplified claude agent completed successfully")
|
|
756
|
+
return True
|
|
757
|
+
return False
|
|
758
|
+
|
|
759
|
+
except KeyboardInterrupt:
|
|
760
|
+
print("\n๐ Execution interrupted by user")
|
|
761
|
+
# Try to gracefully terminate the process
|
|
762
|
+
try:
|
|
763
|
+
sandbox.commands.run("pkill -f 'python.*claude_code_agent.py'", timeout=10)
|
|
764
|
+
except:
|
|
765
|
+
pass
|
|
766
|
+
finally:
|
|
767
|
+
# Clean up the E2B API key from environment when done or on error
|
|
768
|
+
if "E2B_API_KEY" in os.environ:
|
|
769
|
+
del os.environ["E2B_API_KEY"]
|
|
770
|
+
print("๐งน Removed E2B API key from environment")
|
|
771
|
+
return False
|
|
772
|
+
else:
|
|
773
|
+
print("โ ๏ธ No Anthropic API key found")
|
|
715
774
|
return False
|
|
716
|
-
|
|
717
|
-
|
|
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")
|
|
775
|
+
except KeyboardInterrupt:
|
|
776
|
+
print("\n๐ Execution interrupted by user")
|
|
727
777
|
return False
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
778
|
+
except Exception as e:
|
|
779
|
+
print(f"โ E2B sandbox setup failed: {e}")
|
|
780
|
+
return False
|
|
781
|
+
finally:
|
|
782
|
+
# Clean up the E2B API key from environment when done or on error
|
|
783
|
+
if "E2B_API_KEY" in os.environ:
|
|
784
|
+
del os.environ["E2B_API_KEY"]
|
|
785
|
+
print("๐งน Removed E2B API key from environment")
|
|
734
786
|
|
|
735
787
|
def main():
|
|
736
788
|
"""
|
|
@@ -741,6 +793,7 @@ def main():
|
|
|
741
793
|
parser.add_argument("--setup-commands", help="JSON file with setup commands")
|
|
742
794
|
parser.add_argument("--openai-api-key", help="OpenAI API key")
|
|
743
795
|
parser.add_argument("--anthropic-api-key", help="Anthropic API key")
|
|
796
|
+
parser.add_argument("--e2b-api-key", help="E2B API key")
|
|
744
797
|
args = parser.parse_args()
|
|
745
798
|
|
|
746
799
|
# Prepare API keys
|
|
@@ -762,26 +815,33 @@ def main():
|
|
|
762
815
|
try:
|
|
763
816
|
with open(modal_tokens_path, "r") as f:
|
|
764
817
|
modal_tokens = json.load(f)
|
|
765
|
-
if "anthropic_api_key" in modal_tokens:
|
|
818
|
+
if "anthropic_api_key" in modal_tokens and modal_tokens["anthropic_api_key"]:
|
|
766
819
|
api_keys["ANTHROPIC_API_KEY"] = modal_tokens["anthropic_api_key"]
|
|
767
820
|
print("โ
Found Anthropic API key in modal_tokens.json")
|
|
768
821
|
except Exception as e:
|
|
769
822
|
print(f"Error loading modal_tokens.json: {e}")
|
|
770
823
|
|
|
771
|
-
#
|
|
772
|
-
|
|
773
|
-
if args.
|
|
774
|
-
|
|
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}")
|
|
824
|
+
# Check for E2B API key from command line argument only
|
|
825
|
+
# We'll fetch it directly from the server in run_e2b_sandbox if needed
|
|
826
|
+
if args.e2b_api_key:
|
|
827
|
+
api_keys["E2B_API_KEY"] = args.e2b_api_key
|
|
779
828
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
829
|
+
try:
|
|
830
|
+
# Parse setup commands if provided
|
|
831
|
+
setup_commands = None
|
|
832
|
+
if args.setup_commands:
|
|
833
|
+
setup_commands = args.setup_commands
|
|
834
|
+
|
|
835
|
+
# Run the sandbox
|
|
836
|
+
success = run_e2b_sandbox(args.repo, setup_commands, api_keys)
|
|
837
|
+
|
|
838
|
+
# Exit with appropriate code
|
|
839
|
+
sys.exit(0 if success else 1)
|
|
840
|
+
finally:
|
|
841
|
+
# Clean up the E2B API key from environment when done or on error
|
|
842
|
+
if "E2B_API_KEY" in os.environ:
|
|
843
|
+
del os.environ["E2B_API_KEY"]
|
|
844
|
+
print("๐งน Removed E2B API key from environment (main)")
|
|
785
845
|
|
|
786
846
|
if __name__ == "__main__":
|
|
787
847
|
main()
|
|
@@ -194,6 +194,7 @@ if __name__ == "__main__":
|
|
|
194
194
|
parser = argparse.ArgumentParser(description='Fetch Modal tokens and OpenAI API key from the proxy server')
|
|
195
195
|
parser.add_argument('--proxy-url', help='URL of the proxy server')
|
|
196
196
|
parser.add_argument('--proxy-api-key', help='API key for the proxy server')
|
|
197
|
+
parser.add_argument('--output-e2b-key', action='store_true', help='Output the E2B API key directly for JavaScript to use')
|
|
197
198
|
args = parser.parse_args()
|
|
198
199
|
|
|
199
200
|
# Set proxy URL and API key in environment variables if provided
|
|
@@ -207,6 +208,12 @@ if __name__ == "__main__":
|
|
|
207
208
|
|
|
208
209
|
# Get tokens
|
|
209
210
|
token_id, token_secret, e2b_api_key, openai_api_key, anthropic_api_key, openrouter_api_key, groq_api_key = get_tokens()
|
|
211
|
+
|
|
212
|
+
# If --output-e2b-key is specified, output the E2B API key directly
|
|
213
|
+
if args.output_e2b_key and e2b_api_key:
|
|
214
|
+
print(f"E2B_API_KEY={e2b_api_key}")
|
|
215
|
+
sys.exit(0)
|
|
216
|
+
|
|
210
217
|
print(f"Token ID: {token_id}")
|
|
211
218
|
print(f"Token Secret: {token_secret}")
|
|
212
219
|
print(f"E2B API Key: {e2b_api_key[:5] + '...' if e2b_api_key else None}")
|
|
@@ -245,7 +252,8 @@ if __name__ == "__main__":
|
|
|
245
252
|
json.dump({
|
|
246
253
|
"token_id": token_id,
|
|
247
254
|
"token_secret": token_secret,
|
|
248
|
-
|
|
255
|
+
# Don't store the E2B API key
|
|
256
|
+
# "e2b_api_key": e2b_api_key,
|
|
249
257
|
"openai_api_key": openai_api_key,
|
|
250
258
|
"anthropic_api_key": anthropic_api_key,
|
|
251
259
|
"openrouter_api_key": openrouter_api_key,
|
|
@@ -277,16 +285,16 @@ if __name__ == "__main__":
|
|
|
277
285
|
with open(env_file, 'r') as f:
|
|
278
286
|
env_content = f.read()
|
|
279
287
|
|
|
280
|
-
#
|
|
281
|
-
if e2b_api_key:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
# Don't update or add E2B_API_KEY to .env file
|
|
289
|
+
# if e2b_api_key:
|
|
290
|
+
# if "E2B_API_KEY" in env_content:
|
|
291
|
+
# import re
|
|
292
|
+
# env_content = re.sub(r'E2B_API_KEY=.*\n', f'E2B_API_KEY={e2b_api_key}\n', env_content)
|
|
293
|
+
# else:
|
|
294
|
+
# env_content += f'\nE2B_API_KEY={e2b_api_key}\n'
|
|
295
|
+
# with open(env_file, 'w') as f:
|
|
296
|
+
# f.write(env_content)
|
|
297
|
+
# print(f"โ
Updated E2B API key in {env_file}")
|
|
290
298
|
|
|
291
299
|
# Update or add OPENAI_API_KEY
|
|
292
300
|
if openai_api_key:
|
|
@@ -810,9 +810,12 @@ def cleanup_security_tokens():
|
|
|
810
810
|
if var in os.environ:
|
|
811
811
|
del os.environ[var]
|
|
812
812
|
|
|
813
|
-
# Remove
|
|
814
|
-
|
|
815
|
-
|
|
813
|
+
# Remove API keys from environment
|
|
814
|
+
api_keys_to_remove = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "E2B_API_KEY", "OPENROUTER_API_KEY", "GROQ_API_KEY"]
|
|
815
|
+
for key in api_keys_to_remove:
|
|
816
|
+
if key in os.environ:
|
|
817
|
+
del os.environ[key]
|
|
818
|
+
print(f"๐งน Removed {key} from environment")
|
|
816
819
|
|
|
817
820
|
# Delete ~/.modal.toml file
|
|
818
821
|
home_dir = os.path.expanduser("~")
|
|
@@ -1148,6 +1151,12 @@ if __name__ == "__main__":
|
|
|
1148
1151
|
os.environ["OPENAI_API_KEY"] = openai_api_key
|
|
1149
1152
|
if anthropic_api_key:
|
|
1150
1153
|
os.environ["ANTHROPIC_API_KEY"] = anthropic_api_key
|
|
1154
|
+
if e2b_api_key:
|
|
1155
|
+
os.environ["E2B_API_KEY"] = e2b_api_key
|
|
1156
|
+
if openrouter_api_key:
|
|
1157
|
+
os.environ["OPENROUTER_API_KEY"] = openrouter_api_key
|
|
1158
|
+
if groq_api_key:
|
|
1159
|
+
os.environ["GROQ_API_KEY"] = groq_api_key
|
|
1151
1160
|
# Also set the old environment variable for backward compatibility
|
|
1152
1161
|
os.environ["MODAL_TOKEN"] = token_id
|
|
1153
1162
|
|