gitarsenal-cli 1.9.67 ā 1.9.69
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/bin/gitarsenal.js +0 -83
- package/package.json +1 -1
- package/python/test_modalSandboxScript.py +33 -50
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-15T05:02:30.288Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/bin/gitarsenal.js
CHANGED
|
@@ -16,89 +16,6 @@ const fs = require('fs');
|
|
|
16
16
|
const https = require('https');
|
|
17
17
|
const http = require('http');
|
|
18
18
|
|
|
19
|
-
// Function to activate virtual environment
|
|
20
|
-
function activateVirtualEnvironment() {
|
|
21
|
-
const isWindows = process.platform === 'win32';
|
|
22
|
-
const venvPath = path.join(__dirname, '..', '.venv');
|
|
23
|
-
const statusFile = path.join(__dirname, '..', '.venv_status.json');
|
|
24
|
-
|
|
25
|
-
// Check if virtual environment exists
|
|
26
|
-
if (!fs.existsSync(venvPath)) {
|
|
27
|
-
console.log(chalk.red('ā Virtual environment not found. Please reinstall the package:'));
|
|
28
|
-
console.log(chalk.yellow(' npm uninstall -g gitarsenal-cli'));
|
|
29
|
-
console.log(chalk.yellow(' npm install -g gitarsenal-cli'));
|
|
30
|
-
console.log(chalk.yellow(''));
|
|
31
|
-
console.log(chalk.yellow('š” Or run the postinstall script manually:'));
|
|
32
|
-
console.log(chalk.yellow(' cd /root/.nvm/versions/node/v22.18.0/lib/node_modules/gitarsenal-cli'));
|
|
33
|
-
console.log(chalk.yellow(' node scripts/postinstall.js'));
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Check if status file exists (indicates successful installation)
|
|
38
|
-
if (fs.existsSync(statusFile)) {
|
|
39
|
-
try {
|
|
40
|
-
const status = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.log(chalk.gray('ā
Virtual environment found'));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Verify virtual environment structure - uv creates different structure
|
|
47
|
-
let pythonPath, pipPath;
|
|
48
|
-
|
|
49
|
-
// Check for uv-style virtual environment first
|
|
50
|
-
const uvPythonPath = path.join(venvPath, 'bin', 'python');
|
|
51
|
-
const uvPipPath = path.join(venvPath, 'bin', 'pip');
|
|
52
|
-
|
|
53
|
-
// Check for traditional venv structure
|
|
54
|
-
const traditionalPythonPath = isWindows ?
|
|
55
|
-
path.join(venvPath, 'Scripts', 'python.exe') :
|
|
56
|
-
path.join(venvPath, 'bin', 'python');
|
|
57
|
-
const traditionalPipPath = isWindows ?
|
|
58
|
-
path.join(venvPath, 'Scripts', 'pip.exe') :
|
|
59
|
-
path.join(venvPath, 'bin', 'pip');
|
|
60
|
-
|
|
61
|
-
// Determine which structure exists
|
|
62
|
-
// console.log(chalk.gray(`š Checking virtual environment structure:`));
|
|
63
|
-
// console.log(chalk.gray(` Python: ${uvPythonPath} (exists: ${fs.existsSync(uvPythonPath)})`));
|
|
64
|
-
// console.log(chalk.gray(` Pip: ${uvPipPath} (exists: ${fs.existsSync(uvPipPath)})`));
|
|
65
|
-
|
|
66
|
-
// For uv virtual environments, we only need Python to exist
|
|
67
|
-
// uv doesn't create a pip executable, it uses 'uv pip' instead
|
|
68
|
-
if (fs.existsSync(uvPythonPath)) {
|
|
69
|
-
pythonPath = uvPythonPath;
|
|
70
|
-
pipPath = 'uv pip'; // Use uv pip instead of pip executable
|
|
71
|
-
// console.log(chalk.gray('ā
Found uv-style virtual environment'));
|
|
72
|
-
} else if (fs.existsSync(traditionalPythonPath) && fs.existsSync(traditionalPipPath)) {
|
|
73
|
-
pythonPath = traditionalPythonPath;
|
|
74
|
-
pipPath = traditionalPipPath;
|
|
75
|
-
console.log(chalk.gray('ā
Found traditional virtual environment'));
|
|
76
|
-
} else {
|
|
77
|
-
console.log(chalk.red('ā Virtual environment structure not recognized'));
|
|
78
|
-
console.log(chalk.gray('Expected Python at:'));
|
|
79
|
-
console.log(chalk.gray(` ${uvPythonPath}`));
|
|
80
|
-
console.log(chalk.gray(` ${traditionalPythonPath}`));
|
|
81
|
-
console.log(chalk.yellow('š” Please reinstall the package'));
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Update PATH to prioritize virtual environment
|
|
86
|
-
const pathSeparator = isWindows ? ';' : ':';
|
|
87
|
-
const venvBinPath = path.dirname(pythonPath); // Use the same directory as the Python executable
|
|
88
|
-
|
|
89
|
-
process.env.PATH = `${venvBinPath}${pathSeparator}${process.env.PATH}`;
|
|
90
|
-
process.env.VIRTUAL_ENV = venvPath;
|
|
91
|
-
process.env.PYTHONPATH = venvPath;
|
|
92
|
-
|
|
93
|
-
// Set Python executable path for child processes
|
|
94
|
-
process.env.PYTHON_EXECUTABLE = pythonPath;
|
|
95
|
-
process.env.PIP_EXECUTABLE = pipPath;
|
|
96
|
-
|
|
97
|
-
console.log(chalk.green('ā
Virtual environment activated successfully'));
|
|
98
|
-
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
19
|
|
|
103
20
|
// Lightweight preview of GPU/Torch/CUDA recommendations prior to GPU selection
|
|
104
21
|
async function previewRecommendations(repoUrl, optsOrShowSummary = true) {
|
package/package.json
CHANGED
|
@@ -203,8 +203,8 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
203
203
|
volume_name=None, timeout_minutes=60, ssh_password=None, interactive=False, gpu_count=1):
|
|
204
204
|
"""Create a Modal SSH container with GPU support and intelligent repository setup.
|
|
205
205
|
|
|
206
|
-
When repo_url is provided, uses
|
|
207
|
-
The setup_commands parameter is maintained for backwards compatibility but ignored when using
|
|
206
|
+
When repo_url is provided, uses Agent for intelligent repository setup.
|
|
207
|
+
The setup_commands parameter is maintained for backwards compatibility but ignored when using Agent.
|
|
208
208
|
"""
|
|
209
209
|
|
|
210
210
|
# Use interactive mode if specified
|
|
@@ -388,29 +388,12 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
388
388
|
# Set up a nice bash prompt
|
|
389
389
|
"echo 'export PS1=\"\\[\\e[1;32m\\]modal:\\[\\e[1;34m\\]\\w\\[\\e[0m\\]$ \"' >> /root/.bashrc",
|
|
390
390
|
|
|
391
|
-
# Create directories
|
|
392
|
-
"mkdir -p /python
|
|
391
|
+
# Create base directories (subdirectories will be created automatically when mounting)
|
|
392
|
+
"mkdir -p /python",
|
|
393
393
|
)
|
|
394
|
-
# Mount
|
|
395
|
-
.
|
|
396
|
-
.
|
|
397
|
-
.add_local_file(os.path.join(current_dir, "fetch_modal_tokens.py"), "/python/fetch_modal_tokens.py") # Mount fetch_modal_token.py
|
|
398
|
-
.add_local_file(os.path.join(current_dir, "llm_debugging.py"), "/python/llm_debugging.py") # Mount llm_debugging.py
|
|
399
|
-
.add_local_file(os.path.join(current_dir, "credentials_manager.py"), "/python/credentials_manager.py") # Mount credentials_manager.py
|
|
400
|
-
# Mount Claude Code Agent and its dependencies
|
|
401
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "claude_code_agent.py"), "/python/kill_claude/claude_code_agent.py")
|
|
402
|
-
# Mount the tools and prompts directories manually with key files
|
|
403
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "__init__.py"), "/python/kill_claude/tools/__init__.py")
|
|
404
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "bash_tool.py"), "/python/kill_claude/tools/bash_tool.py")
|
|
405
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "read_tool.py"), "/python/kill_claude/tools/read_tool.py")
|
|
406
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "write_tool.py"), "/python/kill_claude/tools/write_tool.py")
|
|
407
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "ls_tool.py"), "/python/kill_claude/tools/ls_tool.py")
|
|
408
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "edit_tool.py"), "/python/kill_claude/tools/edit_tool.py")
|
|
409
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "grep_tool.py"), "/python/kill_claude/tools/grep_tool.py")
|
|
410
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "glob_tool.py"), "/python/kill_claude/tools/glob_tool.py")
|
|
411
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "tools", "todo_write_tool.py"), "/python/kill_claude/tools/todo_write_tool.py")
|
|
412
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "prompts", "claude-code-system-prompt.md"), "/python/kill_claude/prompts/claude-code-system-prompt.md")
|
|
413
|
-
.add_local_file(os.path.join(gitarsenal_root, "kill_claude", "prompts", "claude-code-agent-prompts.md"), "/python/kill_claude/prompts/claude-code-agent-prompts.md")
|
|
394
|
+
# Mount entire directories instead of individual files
|
|
395
|
+
.add_local_dir(current_dir, "/python", ignore=lambda p: not p.name.endswith('.py')) # Mount all Python files from current directory
|
|
396
|
+
.add_local_dir(os.path.join(gitarsenal_root, "kill_claude"), "/python/kill_claude") # Mount entire kill_claude directory with all subdirectories
|
|
414
397
|
|
|
415
398
|
)
|
|
416
399
|
print("ā
SSH image built successfully")
|
|
@@ -437,7 +420,7 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
437
420
|
volumes=volumes_config if volumes_config else None,
|
|
438
421
|
)
|
|
439
422
|
def ssh_container_function(ssh_password=None, repo_url=None, repo_name=None, setup_commands=None, openai_api_key=None, anthropic_api_key=None, stored_credentials=None):
|
|
440
|
-
"""Start SSH container with password authentication and intelligent repository setup using
|
|
423
|
+
"""Start SSH container with password authentication and intelligent repository setup using Agent."""
|
|
441
424
|
import subprocess
|
|
442
425
|
import time
|
|
443
426
|
import os
|
|
@@ -514,11 +497,11 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
514
497
|
# Start SSH service
|
|
515
498
|
subprocess.run(["service", "ssh", "start"], check=True)
|
|
516
499
|
|
|
517
|
-
# Use
|
|
500
|
+
# Use Agent for intelligent repository setup
|
|
518
501
|
if repo_url:
|
|
519
|
-
print("š¤ Using
|
|
502
|
+
print("š¤ Using Agent for intelligent repository setup...")
|
|
520
503
|
|
|
521
|
-
# Set up environment variables for the
|
|
504
|
+
# Set up environment variables for the Agent
|
|
522
505
|
if openai_api_key:
|
|
523
506
|
os.environ['OPENAI_API_KEY'] = openai_api_key
|
|
524
507
|
if anthropic_api_key:
|
|
@@ -537,13 +520,13 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
537
520
|
|
|
538
521
|
if not anthropic_api_key:
|
|
539
522
|
print("ā ļø No Anthropic API key found in stored credentials")
|
|
540
|
-
print("š”
|
|
523
|
+
print("š” Agent will require an Anthropic API key for operation")
|
|
541
524
|
|
|
542
525
|
try:
|
|
543
|
-
print("š§ Running
|
|
526
|
+
print("š§ Running Agent for repository setup...")
|
|
544
527
|
|
|
545
528
|
print("\n" + "="*80)
|
|
546
|
-
print("š¤
|
|
529
|
+
print("š¤ AGENT REPOSITORY SETUP")
|
|
547
530
|
print("="*80)
|
|
548
531
|
print(f"Repository: {repo_url}")
|
|
549
532
|
print(f"Working Directory: /root")
|
|
@@ -551,11 +534,11 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
551
534
|
print(f"Available Credentials: {len(stored_credentials)} items")
|
|
552
535
|
print("="*80 + "\n")
|
|
553
536
|
|
|
554
|
-
# Call
|
|
555
|
-
claude_prompt = f"clone and
|
|
556
|
-
print(f"š Executing
|
|
537
|
+
# Call Agent directly as subprocess with real-time output
|
|
538
|
+
claude_prompt = f"clone, setup and run {repo_url}"
|
|
539
|
+
print(f"š Executing the task: \"{claude_prompt}\"")
|
|
557
540
|
print("\n" + "="*60)
|
|
558
|
-
print("š
|
|
541
|
+
print("š AGENT OUTPUT (LIVE)")
|
|
559
542
|
print("="*60)
|
|
560
543
|
|
|
561
544
|
# Use Popen for real-time output streaming
|
|
@@ -583,13 +566,13 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
583
566
|
|
|
584
567
|
print("\n" + "="*60)
|
|
585
568
|
if return_code == 0:
|
|
586
|
-
print("ā
|
|
569
|
+
print("ā
Agent completed successfully!")
|
|
587
570
|
else:
|
|
588
|
-
print(f"ā ļø
|
|
571
|
+
print(f"ā ļø Agent exited with code: {return_code}")
|
|
589
572
|
print("="*60)
|
|
590
573
|
|
|
591
574
|
except subprocess.TimeoutExpired:
|
|
592
|
-
print("\nā ļø
|
|
575
|
+
print("\nā ļø Agent timed out after 10 minutes")
|
|
593
576
|
process.kill()
|
|
594
577
|
process.wait()
|
|
595
578
|
except Exception as stream_error:
|
|
@@ -1108,10 +1091,10 @@ def show_usage_examples():
|
|
|
1108
1091
|
print("ā gitarsenal --auth # Interactive auth management ā")
|
|
1109
1092
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
1110
1093
|
|
|
1111
|
-
print("Basic Container Creation with
|
|
1094
|
+
print("Basic Container Creation with Agent")
|
|
1112
1095
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
1113
1096
|
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git ā")
|
|
1114
|
-
print("ā #
|
|
1097
|
+
print("ā # Agent will intelligently clone and setup the repository ā")
|
|
1115
1098
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
1116
1099
|
|
|
1117
1100
|
print("With Persistent Storage")
|
|
@@ -1129,13 +1112,13 @@ def show_usage_examples():
|
|
|
1129
1112
|
print("Intelligent Repository Setup (default)")
|
|
1130
1113
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
1131
1114
|
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git ā")
|
|
1132
|
-
print("ā #
|
|
1115
|
+
print("ā # Agent analyzes repo and sets up environment automatically ā")
|
|
1133
1116
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
1134
1117
|
|
|
1135
1118
|
print("With Manual Setup Commands (Advanced)")
|
|
1136
1119
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
1137
1120
|
print("ā gitarsenal --gpu A10G --setup-commands \"pip install torch\" \"python train.py\" ā")
|
|
1138
|
-
print("ā # Only use when not providing --repo-url (bypasses
|
|
1121
|
+
print("ā # Only use when not providing --repo-url (bypasses Agent) ā")
|
|
1139
1122
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
1140
1123
|
|
|
1141
1124
|
print("Development Mode (Skip Authentication)")
|
|
@@ -1157,7 +1140,7 @@ def show_usage_examples():
|
|
|
1157
1140
|
print(" ⢠Without --gpu: Shows interactive GPU selection menu")
|
|
1158
1141
|
print()
|
|
1159
1142
|
print("Repository Setup Behavior:")
|
|
1160
|
-
print(" ⢠With --repo-url
|
|
1143
|
+
print(" ⢠With --repo-url Agent intelligently clones and sets up repository")
|
|
1161
1144
|
print(" ⢠Without --repo-url: Manual container setup (no automatic repository setup)")
|
|
1162
1145
|
print(" ⢠Legacy --setup-commands: Only used when --repo-url not provided")
|
|
1163
1146
|
print()
|
|
@@ -1831,9 +1814,9 @@ if __name__ == "__main__":
|
|
|
1831
1814
|
parser.add_argument('--volume-name', type=str, help='Name of the Modal volume for persistent storage')
|
|
1832
1815
|
parser.add_argument('--timeout', type=int, default=60, help='Container timeout in minutes (default: 60)')
|
|
1833
1816
|
parser.add_argument('--ssh-password', type=str, help='SSH password (random if not provided)')
|
|
1834
|
-
parser.add_argument('--use-api', action='store_true', help='[DEPRECATED] Fetch setup commands from original API (use --repo-url for
|
|
1835
|
-
parser.add_argument('--use-gitingest', action='store_true', default=True, help='[DEPRECATED] Use gitingest approach (
|
|
1836
|
-
parser.add_argument('--no-gitingest', action='store_true', help='[DEPRECATED] Disable gitingest approach (no longer needed with
|
|
1817
|
+
parser.add_argument('--use-api', action='store_true', help='[DEPRECATED] Fetch setup commands from original API (use --repo-url for Agent instead)')
|
|
1818
|
+
parser.add_argument('--use-gitingest', action='store_true', default=True, help='[DEPRECATED] Use gitingest approach (Agent is now used when --repo-url is provided)')
|
|
1819
|
+
parser.add_argument('--no-gitingest', action='store_true', help='[DEPRECATED] Disable gitingest approach (no longer needed with Agent)')
|
|
1837
1820
|
parser.add_argument('--show-examples', action='store_true', help='Show usage examples')
|
|
1838
1821
|
parser.add_argument('--list-gpus', action='store_true', help='List available GPU types with their specifications')
|
|
1839
1822
|
parser.add_argument('--interactive', action='store_true', help='Run in interactive mode with prompts')
|
|
@@ -1966,7 +1949,7 @@ if __name__ == "__main__":
|
|
|
1966
1949
|
print(f"GPU Type: {gpu_type}")
|
|
1967
1950
|
print(f"Volume: {args.volume_name or 'None'}")
|
|
1968
1951
|
if args.repo_url:
|
|
1969
|
-
print("Repository Setup:
|
|
1952
|
+
print("Repository Setup: Agent (intelligent)")
|
|
1970
1953
|
elif args.use_api:
|
|
1971
1954
|
print("Setup Commands: Auto-detect from repository")
|
|
1972
1955
|
elif args.setup_commands:
|
|
@@ -2052,13 +2035,13 @@ if __name__ == "__main__":
|
|
|
2052
2035
|
args.use_gitingest = use_gitingest
|
|
2053
2036
|
|
|
2054
2037
|
try:
|
|
2055
|
-
# Setup commands are no longer used when repo_url is provided (
|
|
2038
|
+
# Setup commands are no longer used when repo_url is provided ( Agent handles setup)
|
|
2056
2039
|
setup_commands = args.setup_commands or []
|
|
2057
2040
|
|
|
2058
2041
|
# Repository setup approach
|
|
2059
2042
|
if args.repo_url:
|
|
2060
|
-
print("š¤ Repository setup will be handled by
|
|
2061
|
-
setup_commands = [] #
|
|
2043
|
+
print("š¤ Repository setup will be handled by Agent in container")
|
|
2044
|
+
setup_commands = [] # Agent will handle setup intelligently
|
|
2062
2045
|
else:
|
|
2063
2046
|
print("ā ļø No repository URL provided - setup commands may be needed manually")
|
|
2064
2047
|
|