gitarsenal-cli 1.9.96 ā 1.9.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.venv_status.json +1 -1
- package/README.md +29 -0
- package/bin/gitarsenal.js +220 -127
- package/kill_claude/requirements.txt +1 -1
- package/lib/dependencies.js +130 -4
- package/lib/e2b-sandbox.js +158 -0
- package/lib/execAsync.js +12 -0
- package/lib/sandbox.js +97 -113
- package/package.json +2 -1
- package/python/__pycache__/credentials_manager.cpython-312.pyc +0 -0
- package/python/__pycache__/e2b_sandbox_agent.cpython-313.pyc +0 -0
- package/python/__pycache__/fetch_modal_tokens.cpython-312.pyc +0 -0
- package/python/credentials_manager.py +2 -1
- package/python/e2b_sandbox_agent.py +787 -0
- package/python/fetch_modal_tokens.py +47 -25
- package/python/requirements.txt +2 -1
- package/python/test_enhanced_sandbox_script.py +1429 -0
- package/python/test_modalSandboxScript.py +41 -5
- package/scripts/setup_e2b.js +162 -0
- package/kill_claude/.claude/settings.local.json +0 -9
- package/kill_claude/__pycache__/bash_output_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/claude_code_agent.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/exit_plan_mode_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/glob_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/grep_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/kill_bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/ls_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/multiedit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/notebook_edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/read_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/task_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/todo_write_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/web_fetch_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/web_search_tool.cpython-313.pyc +0 -0
- package/kill_claude/__pycache__/write_tool.cpython-313.pyc +0 -0
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Modal Sandbox Script for GitArsenal
|
|
5
|
+
--------------------------------
|
|
6
|
+
This script creates a Modal sandbox and sets up a repository.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
import os
|
|
2
10
|
import sys
|
|
3
11
|
import time
|
|
@@ -10,7 +18,15 @@ import secrets
|
|
|
10
18
|
import string
|
|
11
19
|
import argparse
|
|
12
20
|
from pathlib import Path
|
|
13
|
-
|
|
21
|
+
|
|
22
|
+
# Try to import modal, but don't attempt to install it
|
|
23
|
+
try:
|
|
24
|
+
import modal
|
|
25
|
+
except ImportError:
|
|
26
|
+
print("ā Error: Modal package not found.")
|
|
27
|
+
print("Please install the required packages manually with:")
|
|
28
|
+
print("pip install modal python-dotenv e2b-code-interpreter")
|
|
29
|
+
sys.exit(1)
|
|
14
30
|
|
|
15
31
|
|
|
16
32
|
def generate_random_password(length=16):
|
|
@@ -284,7 +300,7 @@ def ssh_container_function(ssh_password=None, repo_url=None, repo_name=None, set
|
|
|
284
300
|
|
|
285
301
|
# Call Agent directly as subprocess with real-time output
|
|
286
302
|
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."
|
|
287
|
-
print(f"š Executing the task: \"{claude_prompt}\"")
|
|
303
|
+
# print(f"š Executing the task: \"{claude_prompt}\"")
|
|
288
304
|
print("\n" + "="*60)
|
|
289
305
|
print("š AGENT OUTPUT (LIVE)")
|
|
290
306
|
print("="*60)
|
|
@@ -834,12 +850,24 @@ def show_usage_examples():
|
|
|
834
850
|
print("ā gitarsenal --auth # Interactive auth management ā")
|
|
835
851
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
836
852
|
|
|
853
|
+
print("Sandbox Provider Options")
|
|
854
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
855
|
+
print("ā gitarsenal --sandbox-provider modal # Use Modal sandbox (default, GPU support) ā")
|
|
856
|
+
print("ā gitarsenal --sandbox-provider e2b # Use E2B sandbox (faster startup) ā")
|
|
857
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
858
|
+
|
|
837
859
|
print("Basic Container Creation with Agent")
|
|
838
860
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
839
861
|
print("ā gitarsenal --gpu A10G --repo https://github.com/username/repo.git ā")
|
|
840
862
|
print("ā # Agent will intelligently clone and setup the repository ā")
|
|
841
863
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
842
864
|
|
|
865
|
+
print("With E2B Sandbox Provider")
|
|
866
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
867
|
+
print("ā gitarsenal --sandbox-provider e2b --repo https://github.com/username/repo.git ā")
|
|
868
|
+
print("ā # Uses E2B sandbox instead of Modal (no GPU but faster startup) ā")
|
|
869
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
870
|
+
|
|
843
871
|
print("With Persistent Storage")
|
|
844
872
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
845
873
|
print("ā gitarsenal --gpu A10G --repo https://github.com/username/repo.git \\ ā")
|
|
@@ -873,6 +901,10 @@ def show_usage_examples():
|
|
|
873
901
|
print(" T4, L4, A10G, A100-40GB, A100-80GB, L40S, H100, H200, B200")
|
|
874
902
|
print(" Use --gpu-count to specify multiple GPUs (1-8)")
|
|
875
903
|
print()
|
|
904
|
+
print("Sandbox Provider Options:")
|
|
905
|
+
print(" modal: GPU support, persistent volumes (default)")
|
|
906
|
+
print(" e2b: Faster startup, no GPU support")
|
|
907
|
+
print()
|
|
876
908
|
print("Authentication Behavior:")
|
|
877
909
|
print(" ⢠First time: Interactive registration/login required")
|
|
878
910
|
print(" ⢠Subsequent runs: Automatic login with stored session")
|
|
@@ -881,6 +913,7 @@ def show_usage_examples():
|
|
|
881
913
|
print("GPU Selection Behavior:")
|
|
882
914
|
print(" ⢠With --gpu: Uses specified GPU without prompting")
|
|
883
915
|
print(" ⢠Without --gpu: Shows interactive GPU selection menu")
|
|
916
|
+
print(" ⢠Not applicable for E2B sandbox provider")
|
|
884
917
|
print()
|
|
885
918
|
print("Repository Setup Behavior:")
|
|
886
919
|
print(" ⢠With --repo Agent intelligently clones and sets up repository")
|
|
@@ -888,9 +921,12 @@ def show_usage_examples():
|
|
|
888
921
|
print(" ⢠Legacy --setup-commands: Only used when --repo not provided")
|
|
889
922
|
print()
|
|
890
923
|
print("Examples:")
|
|
891
|
-
print(" # Intelligent repository setup (recommended):")
|
|
924
|
+
print(" # Intelligent repository setup with Modal (recommended):")
|
|
892
925
|
print(" gitarsenal --gpu A10G --repo https://github.com/username/repo.git")
|
|
893
926
|
print()
|
|
927
|
+
print(" # Using E2B sandbox provider:")
|
|
928
|
+
print(" gitarsenal --sandbox-provider e2b --repo https://github.com/username/repo.git")
|
|
929
|
+
print()
|
|
894
930
|
print(" # Development mode (skip authentication):")
|
|
895
931
|
print(" gitarsenal --skip-auth --gpu A10G --repo https://github.com/username/repo.git")
|
|
896
932
|
print()
|
|
@@ -1099,7 +1135,7 @@ if __name__ == "__main__":
|
|
|
1099
1135
|
|
|
1100
1136
|
# Initialize tokens (import here to avoid container import issues)
|
|
1101
1137
|
from fetch_modal_tokens import get_tokens
|
|
1102
|
-
token_id, token_secret, openai_api_key, anthropic_api_key, openrouter_api_key, groq_api_key = get_tokens()
|
|
1138
|
+
token_id, token_secret, openai_api_key, e2b_api_key, anthropic_api_key, openrouter_api_key, groq_api_key = get_tokens()
|
|
1103
1139
|
|
|
1104
1140
|
# Check if we got valid tokens
|
|
1105
1141
|
if token_id is None or token_secret is None:
|
|
@@ -1383,7 +1419,7 @@ if __name__ == "__main__":
|
|
|
1383
1419
|
else:
|
|
1384
1420
|
ssh_password = generate_random_password()
|
|
1385
1421
|
print(f"š Generated random SSH password: {ssh_password}")
|
|
1386
|
-
|
|
1422
|
+
|
|
1387
1423
|
# Extract repository name from URL if not provided
|
|
1388
1424
|
repo_name = args.repo_name
|
|
1389
1425
|
if not repo_name and args.repo_url:
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
async function setupE2B() {
|
|
10
|
+
console.log(chalk.blue('š§ E2B Sandbox Setup'));
|
|
11
|
+
console.log(chalk.gray('This script will help you set up the E2B API key for GitArsenal.'));
|
|
12
|
+
console.log(chalk.gray('You can get your API key by signing up at https://e2b.dev'));
|
|
13
|
+
console.log();
|
|
14
|
+
|
|
15
|
+
// Check if E2B_API_KEY is already set in environment
|
|
16
|
+
const existingKey = process.env.E2B_API_KEY;
|
|
17
|
+
if (existingKey) {
|
|
18
|
+
console.log(chalk.green('ā
E2B API key is already set in your environment.'));
|
|
19
|
+
console.log(chalk.gray(`Key: ${existingKey.substring(0, 4)}...${existingKey.substring(existingKey.length - 4)}`));
|
|
20
|
+
|
|
21
|
+
const { updateKey } = await inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'confirm',
|
|
24
|
+
name: 'updateKey',
|
|
25
|
+
message: 'Do you want to update your E2B API key?',
|
|
26
|
+
default: false
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
if (!updateKey) {
|
|
31
|
+
console.log(chalk.green('ā
Using existing E2B API key.'));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Prompt for E2B API key
|
|
37
|
+
const { apiKey } = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'password',
|
|
40
|
+
name: 'apiKey',
|
|
41
|
+
message: 'Enter your E2B API key:',
|
|
42
|
+
mask: '*',
|
|
43
|
+
validate: (input) => {
|
|
44
|
+
if (!input.trim()) {
|
|
45
|
+
return 'API key is required';
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
// Determine where to store the API key
|
|
53
|
+
const { storeLocation } = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'list',
|
|
56
|
+
name: 'storeLocation',
|
|
57
|
+
message: 'Where would you like to store the API key?',
|
|
58
|
+
choices: [
|
|
59
|
+
{ name: 'Environment variable (this session only)', value: 'env' },
|
|
60
|
+
{ name: '.env file in current directory', value: 'local' },
|
|
61
|
+
{ name: '.env file in home directory', value: 'home' }
|
|
62
|
+
],
|
|
63
|
+
default: 'env'
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
// Store the API key based on user's choice
|
|
68
|
+
switch (storeLocation) {
|
|
69
|
+
case 'env':
|
|
70
|
+
process.env.E2B_API_KEY = apiKey;
|
|
71
|
+
console.log(chalk.green('ā
E2B API key set for this session.'));
|
|
72
|
+
console.log(chalk.yellow('ā ļø This setting will be lost when you close your terminal.'));
|
|
73
|
+
console.log(chalk.gray('To make it permanent, add the following to your shell profile:'));
|
|
74
|
+
console.log(chalk.cyan(`export E2B_API_KEY="${apiKey}"`));
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'local':
|
|
78
|
+
try {
|
|
79
|
+
const envFile = path.join(process.cwd(), '.env');
|
|
80
|
+
let content = '';
|
|
81
|
+
|
|
82
|
+
if (fs.existsSync(envFile)) {
|
|
83
|
+
content = fs.readFileSync(envFile, 'utf8');
|
|
84
|
+
// Replace existing E2B_API_KEY if it exists
|
|
85
|
+
if (content.match(/^E2B_API_KEY=.*/m)) {
|
|
86
|
+
content = content.replace(/^E2B_API_KEY=.*/m, `E2B_API_KEY="${apiKey}"`);
|
|
87
|
+
} else {
|
|
88
|
+
content += `\nE2B_API_KEY="${apiKey}"\n`;
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
content = `E2B_API_KEY="${apiKey}"\n`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fs.writeFileSync(envFile, content);
|
|
95
|
+
console.log(chalk.green(`ā
E2B API key saved to ${envFile}`));
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(chalk.red(`ā Failed to save API key to .env file: ${error.message}`));
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
|
|
101
|
+
case 'home':
|
|
102
|
+
try {
|
|
103
|
+
const homeDir = os.homedir();
|
|
104
|
+
const envFile = path.join(homeDir, '.env');
|
|
105
|
+
let content = '';
|
|
106
|
+
|
|
107
|
+
if (fs.existsSync(envFile)) {
|
|
108
|
+
content = fs.readFileSync(envFile, 'utf8');
|
|
109
|
+
// Replace existing E2B_API_KEY if it exists
|
|
110
|
+
if (content.match(/^E2B_API_KEY=.*/m)) {
|
|
111
|
+
content = content.replace(/^E2B_API_KEY=.*/m, `E2B_API_KEY="${apiKey}"`);
|
|
112
|
+
} else {
|
|
113
|
+
content += `\nE2B_API_KEY="${apiKey}"\n`;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
content = `E2B_API_KEY="${apiKey}"\n`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fs.writeFileSync(envFile, content);
|
|
120
|
+
console.log(chalk.green(`ā
E2B API key saved to ${envFile}`));
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error(chalk.red(`ā Failed to save API key to home .env file: ${error.message}`));
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Also store in GitArsenal credentials
|
|
128
|
+
try {
|
|
129
|
+
const gitarsenalDir = path.join(os.homedir(), '.gitarsenal');
|
|
130
|
+
if (!fs.existsSync(gitarsenalDir)) {
|
|
131
|
+
fs.mkdirSync(gitarsenalDir, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const credentialsFile = path.join(gitarsenalDir, 'credentials.json');
|
|
135
|
+
let credentials = {};
|
|
136
|
+
|
|
137
|
+
if (fs.existsSync(credentialsFile)) {
|
|
138
|
+
try {
|
|
139
|
+
credentials = JSON.parse(fs.readFileSync(credentialsFile, 'utf8'));
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.log(chalk.yellow(`ā ļø Could not read existing credentials file: ${error.message}`));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
credentials['e2b'] = apiKey;
|
|
146
|
+
fs.writeFileSync(credentialsFile, JSON.stringify(credentials, null, 2));
|
|
147
|
+
console.log(chalk.green('ā
E2B API key also saved to GitArsenal credentials.'));
|
|
148
|
+
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error(chalk.red(`ā Failed to save API key to GitArsenal credentials: ${error.message}`));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(chalk.green('\nš E2B setup complete! You can now use the E2B sandbox provider.'));
|
|
154
|
+
console.log(chalk.cyan('To use E2B sandbox, run:'));
|
|
155
|
+
console.log(chalk.white(' gitarsenal --sandbox-provider e2b --repo <repository-url>'));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Run the setup
|
|
159
|
+
setupE2B().catch(error => {
|
|
160
|
+
console.error(chalk.red(`ā Error: ${error.message}`));
|
|
161
|
+
process.exit(1);
|
|
162
|
+
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|