gitarsenal-cli 1.9.97 โ†’ 1.9.98

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 CHANGED
@@ -1 +1 @@
1
- {"created":"2025-09-13T16:50:38.652Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
1
+ {"created":"2025-09-14T10:39:18.686Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
@@ -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
- console.log(chalk.green('โœ… Using E2B API key from apiKeys'));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitarsenal-cli",
3
- "version": "1.9.97",
3
+ "version": "1.9.98",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -482,29 +482,74 @@ def run_e2b_sandbox(repo_url, setup_commands=None, api_keys=None):
482
482
  """
483
483
  print("๐Ÿ”„ Creating E2B sandbox...")
484
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")
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
- # Verify package installation
503
- result = sandbox.commands.run("pip list | grep -E 'anthropic|typer|rich'")
504
- print(f"Installed packages verification: {result.stdout}")
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
+ print(f"โœ… Successfully fetched E2B API key from server (format: {e2b_api_key[:6]}...)")
495
+ else:
496
+ print("โš ๏ธ Could not get valid E2B API key from server")
497
+ e2b_api_key = None
498
+ except Exception as e:
499
+ print(f"โš ๏ธ Could not fetch E2B API key from server: {e}")
500
+ e2b_api_key = None
501
+
502
+ # If we couldn't fetch the key directly, check if it's in api_keys
503
+ if not e2b_api_key and api_keys and "E2B_API_KEY" in api_keys:
504
+ e2b_api_key = api_keys["E2B_API_KEY"]
505
+ # Check if the key from api_keys is a placeholder
506
+ if e2b_api_key == "your_e2b_api_key" or e2b_api_key.startswith("placeholder"):
507
+ print("โš ๏ธ Found placeholder E2B API key in api_keys")
508
+ e2b_api_key = None
509
+ else:
510
+ os.environ["E2B_API_KEY"] = e2b_api_key
511
+ print("โœ… Using E2B API key from api_keys")
512
+
513
+ # Last resort: check environment
514
+ if not e2b_api_key:
515
+ e2b_api_key = os.environ.get("E2B_API_KEY")
516
+ # Check if the key is a placeholder value
517
+ if e2b_api_key and (e2b_api_key == "your_e2b_api_key" or e2b_api_key.startswith("placeholder")):
518
+ print("โš ๏ธ Found placeholder E2B API key in environment")
519
+ e2b_api_key = None
520
+
521
+ if not e2b_api_key:
522
+ print("โŒ E2B API key not found")
523
+ print("Please set the E2B_API_KEY environment variable or add it to your API keys")
524
+ return False
505
525
 
506
- # Create a wrapper script to run claude_code_agent.py
507
- wrapper_script = """#!/usr/bin/env python3
526
+ # Debug logging for E2B API key format (only show prefix)
527
+ print(f"๐Ÿ” E2B API key format check: starts with '{e2b_api_key[:6]}', length: {len(e2b_api_key)}")
528
+
529
+ try:
530
+ # Create a new E2B sandbox with a longer timeout (30 minutes)
531
+ sandbox = Sandbox.create(timeout=1800)
532
+ print("โœ… E2B sandbox created successfully (30 minute timeout)")
533
+
534
+ # Install required packages
535
+ print("๐Ÿ“ฆ Installing required packages in sandbox...")
536
+ install_dependencies_in_sandbox(sandbox)
537
+
538
+ # Upload claude_code_agent.py and related files
539
+ upload_claude_agent_to_sandbox(sandbox)
540
+ print("๐Ÿ“ฆ Installing required packages for claude_code_agent...")
541
+ result = sandbox.commands.run("cd /home/user/kill_claude && pip install -r requirements.txt")
542
+ if result.exit_code != 0:
543
+ print(f"โš ๏ธ Failed to install requirements for claude_code_agent: {result.stderr}")
544
+ else:
545
+ print("โœ… Successfully installed requirements for claude_code_agent")
546
+
547
+ # Verify package installation
548
+ result = sandbox.commands.run("pip list | grep -E 'anthropic|typer|rich'")
549
+ print(f"Installed packages verification: {result.stdout}")
550
+
551
+ # Create a wrapper script to run claude_code_agent.py
552
+ wrapper_script = """#!/usr/bin/env python3
508
553
  import sys
509
554
  import os
510
555
  import subprocess
@@ -535,83 +580,83 @@ if __name__ == "__main__":
535
580
  traceback.print_exc()
536
581
  sys.exit(1)
537
582
  """
538
-
539
- sandbox.run_code(f"""
583
+
584
+ sandbox.run_code(f"""
540
585
  with open('/home/user/run_claude_agent.py', 'w') as f:
541
586
  f.write({repr(wrapper_script)})
542
587
  print("โœ… Created wrapper script for claude_code_agent.py")
543
588
  """)
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"""
589
+
590
+ # List the contents of the kill_claude directory
591
+ print("๐Ÿ“‚ Listing contents of kill_claude directory:")
592
+ result = sandbox.commands.run("ls -la /home/user/kill_claude")
593
+ print(result.stdout)
594
+
595
+ # List the contents of the tools directory
596
+ print("๐Ÿ“‚ Listing contents of kill_claude/tools directory:")
597
+ result = sandbox.commands.run("ls -la /home/user/kill_claude/tools")
598
+ print(result.stdout)
599
+
600
+ # List the contents of the prompts directory
601
+ print("๐Ÿ“‚ Listing contents of kill_claude/prompts directory:")
602
+ result = sandbox.commands.run("ls -la /home/user/kill_claude/prompts")
603
+ print(result.stdout)
604
+
605
+ # Find the Python executable path
606
+ result = sandbox.commands.run("which python")
607
+ python_path = result.stdout.strip()
608
+ print(f"Python executable path: {python_path}")
609
+
610
+ # Test Python interpreter
611
+ result = sandbox.commands.run("python -c \"print('Python interpreter test')\"")
612
+ if result.exit_code == 0:
613
+ print("โœ… Python interpreter is working correctly")
614
+ else:
615
+ print("โŒ Python interpreter test failed")
616
+ print(f"Error: {result.stderr}")
617
+
618
+ # Set up API keys in the sandbox environment
619
+ if api_keys:
620
+ for key_name, key_value in api_keys.items():
621
+ if key_value:
622
+ # Set environment variable in the sandbox
623
+ sandbox.run_code(f"""
579
624
  import os
580
625
  os.environ['{key_name}'] = '{key_value}'
581
626
  print(f"โœ… Set {key_name} in sandbox environment")
582
627
  """)
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
628
 
606
- # Run the claude_code_agent.py directly with the environment variable
607
- print("๐Ÿ“ Running claude_code_agent.py directly...")
629
+ print("\n" + "="*80)
630
+ print("๐Ÿค– CLAUDE AGENT REPOSITORY SETUP")
631
+ print("="*80)
632
+ print(f"Repository: {repo_url}")
633
+ print(f"Working Directory: /home/user")
634
+ print(f"Available Credentials: {len(api_keys) if api_keys else 0} items")
635
+ print("="*80 + "\n")
636
+
637
+ print("\n" + "="*60)
638
+ print("๐ŸŽ‰ AGENT OUTPUT (LIVE)")
639
+ print("="*60)
608
640
 
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}")
641
+ # Create a prompt for the agent
642
+ 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."
612
643
 
613
- # Test importing the module
614
- import_test = sandbox.run_code("""
644
+ # Set environment variables directly in the command
645
+ print("๐Ÿš€ Running claude_code_agent.py...")
646
+ if api_keys and 'ANTHROPIC_API_KEY' in api_keys:
647
+ anthropic_key = api_keys['ANTHROPIC_API_KEY']
648
+ # Print the first few characters of the API key to verify it's being passed correctly
649
+ print(f"โœ… Using Anthropic API key: {anthropic_key[:8]}...")
650
+
651
+ # Run the claude_code_agent.py directly with the environment variable
652
+ print("๐Ÿ“ Running claude_code_agent.py directly...")
653
+
654
+ # Debug: Check if the file exists and is executable
655
+ result = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
656
+ print(f"File check: {result.stdout}")
657
+
658
+ # Test importing the module
659
+ import_test = sandbox.run_code("""
615
660
  try:
616
661
  import sys
617
662
  sys.path.append('/home/user')
@@ -640,97 +685,107 @@ try:
640
685
  except Exception as e:
641
686
  print(f"โŒ Failed to import claude_code_agent module: {e}")
642
687
  """)
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
688
 
663
- print(f"Claude agent exit code: {result.exit_code}")
689
+ # Now run the actual command with more debugging
690
+ print("๐Ÿ“ Running claude_code_agent.py with debugging...")
664
691
 
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
692
+ # Try with a simpler approach - just the query subcommand
693
+ debug_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
694
+ print("Command to execute:", debug_cmd)
681
695
 
682
- # Use the simple agent as a fallback
683
- print("Will use simple agent as a fallback if needed...")
696
+ # Define stdout and stderr handlers to stream output in real-time
697
+ def on_stdout(data):
698
+ print(data.strip())
684
699
 
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}")
700
+ def on_stderr(data):
701
+ print(f"STDERR: {data.strip()}")
690
702
 
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}")
703
+ # Run the command with streaming output
704
+ print("Starting command execution with streaming output...")
705
+ try:
706
+ result = sandbox.commands.run(debug_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
707
+
708
+ print(f"Claude agent exit code: {result.exit_code}")
711
709
 
712
- if simple_result.exit_code == 0:
713
- print("โœ… Simplified claude agent completed successfully")
710
+ if result.exit_code != 0:
711
+ print(f"โš ๏ธ Claude agent failed with exit code {result.exit_code}")
712
+
713
+ # Try to diagnose the issue
714
+ print("๐Ÿ” Diagnosing the issue...")
715
+
716
+ # Check if the file exists
717
+ file_check = sandbox.commands.run("ls -la /home/user/kill_claude/claude_code_agent.py")
718
+ print(f"File exists: {file_check.exit_code == 0}")
719
+
720
+ # Check Python version
721
+ python_version = sandbox.commands.run("python --version")
722
+ print(f"Python version: {python_version.stdout}")
723
+ else:
724
+ print("โœ… Claude agent completed successfully")
714
725
  return True
726
+
727
+ # Use the simple agent as a fallback
728
+ print("Will use simple agent as a fallback if needed...")
729
+
730
+ # Try using the wrapper script
731
+ print("Trying wrapper script execution method...")
732
+ wrapper_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python run_claude_agent.py \"{claude_prompt}\""
733
+ wrapper_result = sandbox.commands.run(wrapper_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
734
+ print(f"Wrapper script execution result: {wrapper_result.exit_code}")
735
+
736
+ if wrapper_result.exit_code == 0:
737
+ print("โœ… Claude agent completed successfully using wrapper script")
738
+ return True
739
+
740
+ # Try direct command with query
741
+ print("Trying direct command with query subcommand...")
742
+ direct_cmd = f"cd /home/user && ANTHROPIC_API_KEY=\"{anthropic_key}\" python /home/user/kill_claude/claude_code_agent.py query \"{claude_prompt}\""
743
+ direct_result = sandbox.commands.run(direct_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
744
+ print(f"Direct command result: {direct_result.exit_code}")
745
+
746
+ if direct_result.exit_code == 0:
747
+ print("โœ… Claude agent completed successfully using direct command")
748
+ return True
749
+
750
+ # Final fallback: Create and use a simple agent
751
+ print("๐Ÿ”„ Falling back to simple agent...")
752
+ if create_simple_agent_script(sandbox):
753
+ simple_cmd = f"cd /home/user && python simple_agent.py \"{repo_url}\""
754
+ simple_result = sandbox.commands.run(simple_cmd, timeout=1800, on_stdout=on_stdout, on_stderr=on_stderr)
755
+ print(f"Simple agent result: {simple_result.exit_code}")
756
+
757
+ if simple_result.exit_code == 0:
758
+ print("โœ… Simplified claude agent completed successfully")
759
+ return True
760
+ return False
761
+
762
+ except KeyboardInterrupt:
763
+ print("\n๐Ÿ›‘ Execution interrupted by user")
764
+ # Try to gracefully terminate the process
765
+ try:
766
+ sandbox.commands.run("pkill -f 'python.*claude_code_agent.py'", timeout=10)
767
+ except:
768
+ pass
769
+ finally:
770
+ # Clean up the E2B API key from environment when done or on error
771
+ if "E2B_API_KEY" in os.environ:
772
+ del os.environ["E2B_API_KEY"]
773
+ print("๐Ÿงน Removed E2B API key from environment")
774
+ return False
775
+ else:
776
+ print("โš ๏ธ No Anthropic API key found")
715
777
  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")
778
+ except KeyboardInterrupt:
779
+ print("\n๐Ÿ›‘ Execution interrupted by user")
727
780
  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
781
+ except Exception as e:
782
+ print(f"โŒ E2B sandbox setup failed: {e}")
783
+ return False
784
+ finally:
785
+ # Clean up the E2B API key from environment when done or on error
786
+ if "E2B_API_KEY" in os.environ:
787
+ del os.environ["E2B_API_KEY"]
788
+ print("๐Ÿงน Removed E2B API key from environment")
734
789
 
735
790
  def main():
736
791
  """
@@ -741,6 +796,7 @@ def main():
741
796
  parser.add_argument("--setup-commands", help="JSON file with setup commands")
742
797
  parser.add_argument("--openai-api-key", help="OpenAI API key")
743
798
  parser.add_argument("--anthropic-api-key", help="Anthropic API key")
799
+ parser.add_argument("--e2b-api-key", help="E2B API key")
744
800
  args = parser.parse_args()
745
801
 
746
802
  # Prepare API keys
@@ -762,26 +818,33 @@ def main():
762
818
  try:
763
819
  with open(modal_tokens_path, "r") as f:
764
820
  modal_tokens = json.load(f)
765
- if "anthropic_api_key" in modal_tokens:
821
+ if "anthropic_api_key" in modal_tokens and modal_tokens["anthropic_api_key"]:
766
822
  api_keys["ANTHROPIC_API_KEY"] = modal_tokens["anthropic_api_key"]
767
823
  print("โœ… Found Anthropic API key in modal_tokens.json")
768
824
  except Exception as e:
769
825
  print(f"Error loading modal_tokens.json: {e}")
770
826
 
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}")
827
+ # Check for E2B API key from command line argument only
828
+ # We'll fetch it directly from the server in run_e2b_sandbox if needed
829
+ if args.e2b_api_key:
830
+ api_keys["E2B_API_KEY"] = args.e2b_api_key
779
831
 
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)
832
+ try:
833
+ # Parse setup commands if provided
834
+ setup_commands = None
835
+ if args.setup_commands:
836
+ setup_commands = args.setup_commands
837
+
838
+ # Run the sandbox
839
+ success = run_e2b_sandbox(args.repo, setup_commands, api_keys)
840
+
841
+ # Exit with appropriate code
842
+ sys.exit(0 if success else 1)
843
+ finally:
844
+ # Clean up the E2B API key from environment when done or on error
845
+ if "E2B_API_KEY" in os.environ:
846
+ del os.environ["E2B_API_KEY"]
847
+ print("๐Ÿงน Removed E2B API key from environment (main)")
785
848
 
786
849
  if __name__ == "__main__":
787
850
  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
- "e2b_api_key": e2b_api_key,
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
- # Update or add E2B_API_KEY
281
- if e2b_api_key:
282
- if "E2B_API_KEY" in env_content:
283
- import re
284
- env_content = re.sub(r'E2B_API_KEY=.*\n', f'E2B_API_KEY={e2b_api_key}\n', env_content)
285
- else:
286
- env_content += f'\nE2B_API_KEY={e2b_api_key}\n'
287
- with open(env_file, 'w') as f:
288
- f.write(env_content)
289
- print(f"โœ… Updated E2B API key in {env_file}")
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 OpenAI API key from environment
814
- if "OPENAI_API_KEY" in os.environ:
815
- del os.environ["OPENAI_API_KEY"]
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