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 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:44:37.356Z","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.99",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -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
- # 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
+ 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
- # Create a wrapper script to run claude_code_agent.py
507
- wrapper_script = """#!/usr/bin/env python3
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
- sandbox.run_code(f"""
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
- # 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"""
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
- # Run the claude_code_agent.py directly with the environment variable
607
- print("๐Ÿ“ Running claude_code_agent.py directly...")
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
- # 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}")
634
+ print("\n" + "="*60)
635
+ print("๐ŸŽ‰ AGENT OUTPUT (LIVE)")
636
+ print("="*60)
612
637
 
613
- # Test importing the module
614
- import_test = sandbox.run_code("""
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
- # 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}")
686
+ # Now run the actual command with more debugging
687
+ print("๐Ÿ“ Running claude_code_agent.py with debugging...")
690
688
 
691
- if wrapper_result.exit_code == 0:
692
- print("โœ… Claude agent completed successfully using wrapper script")
693
- return True
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
- # 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}")
693
+ # Define stdout and stderr handlers to stream output in real-time
694
+ def on_stdout(data):
695
+ print(data.strip())
700
696
 
701
- if direct_result.exit_code == 0:
702
- print("โœ… Claude agent completed successfully using direct command")
703
- return True
697
+ def on_stderr(data):
698
+ print(f"STDERR: {data.strip()}")
704
699
 
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}")
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 simple_result.exit_code == 0:
713
- print("โœ… Simplified claude agent completed successfully")
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
- 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")
775
+ except KeyboardInterrupt:
776
+ print("\n๐Ÿ›‘ Execution interrupted by user")
727
777
  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
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
- # 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}")
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
- # 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)
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
- "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