gitarsenal-cli 1.9.10 ā 1.9.12
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 +12 -2
- package/lib/sandbox.js +9 -1
- package/package.json +1 -1
- package/python/documentation.py +76 -0
- package/python/test_modalSandboxScript.py +19 -402
- package/test_modalSandboxScript.py +19 -399
- package/__pycache__/test_modalSandboxScript.cpython-313.pyc +0 -0
- package/eval_repos.py +0 -1
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-05T14:22:25.927Z","packages":["modal","gitingest","requests"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/bin/gitarsenal.js
CHANGED
|
@@ -347,6 +347,7 @@ program.parse(process.argv);
|
|
|
347
347
|
|
|
348
348
|
async function runContainerCommand(options) {
|
|
349
349
|
try {
|
|
350
|
+
console.log(chalk.blue('š DEBUG: runContainerCommand called with options:'), options);
|
|
350
351
|
// If show-examples flag is set, just show examples and exit
|
|
351
352
|
if (options.showExamples) {
|
|
352
353
|
await runContainer({
|
|
@@ -419,7 +420,7 @@ async function runContainerCommand(options) {
|
|
|
419
420
|
}
|
|
420
421
|
|
|
421
422
|
// Prompt for persistent volume
|
|
422
|
-
if (!volumeName) {
|
|
423
|
+
if (!volumeName && !skipConfirmation) {
|
|
423
424
|
const volumeAnswers = await inquirer.prompt([
|
|
424
425
|
{
|
|
425
426
|
type: 'confirm',
|
|
@@ -439,6 +440,9 @@ async function runContainerCommand(options) {
|
|
|
439
440
|
if (volumeAnswers.useVolume) {
|
|
440
441
|
volumeName = volumeAnswers.volumeName;
|
|
441
442
|
}
|
|
443
|
+
} else if (!volumeName && skipConfirmation) {
|
|
444
|
+
// If --yes flag is used and no volume specified, use default
|
|
445
|
+
volumeName = 'gitarsenal-volume';
|
|
442
446
|
}
|
|
443
447
|
|
|
444
448
|
// Ask about setup command detection if not specified via CLI
|
|
@@ -453,6 +457,9 @@ async function runContainerCommand(options) {
|
|
|
453
457
|
]);
|
|
454
458
|
|
|
455
459
|
useApi = apiAnswers.useApi;
|
|
460
|
+
} else if (options.yes) {
|
|
461
|
+
// If --yes flag is used, default to using API for setup command detection
|
|
462
|
+
useApi = true;
|
|
456
463
|
}
|
|
457
464
|
|
|
458
465
|
// Only prompt for custom commands if auto-detection is disabled and no commands provided
|
|
@@ -485,6 +492,7 @@ async function runContainerCommand(options) {
|
|
|
485
492
|
}
|
|
486
493
|
|
|
487
494
|
// Confirm settings (configuration will be shown by Python script after GPU selection)
|
|
495
|
+
console.log(chalk.gray(`š Debug: skipConfirmation = ${skipConfirmation}, options.yes = ${options.yes}`));
|
|
488
496
|
if (!skipConfirmation) {
|
|
489
497
|
const confirmAnswers = await inquirer.prompt([
|
|
490
498
|
{
|
|
@@ -506,12 +514,14 @@ async function runContainerCommand(options) {
|
|
|
506
514
|
|
|
507
515
|
// Run the container
|
|
508
516
|
try {
|
|
517
|
+
console.log(chalk.gray(`š Debug: skipConfirmation = ${skipConfirmation}`));
|
|
509
518
|
await runContainer({
|
|
510
519
|
repoUrl,
|
|
511
520
|
gpuType,
|
|
512
521
|
volumeName,
|
|
513
522
|
setupCommands,
|
|
514
|
-
useApi
|
|
523
|
+
useApi,
|
|
524
|
+
yes: skipConfirmation
|
|
515
525
|
});
|
|
516
526
|
|
|
517
527
|
} catch (containerError) {
|
package/lib/sandbox.js
CHANGED
|
@@ -43,7 +43,8 @@ async function runContainer(options) {
|
|
|
43
43
|
volumeName,
|
|
44
44
|
setupCommands = [],
|
|
45
45
|
useApi = true,
|
|
46
|
-
showExamples = false
|
|
46
|
+
showExamples = false,
|
|
47
|
+
yes = false
|
|
47
48
|
} = options;
|
|
48
49
|
|
|
49
50
|
// Get the path to the Python script
|
|
@@ -100,6 +101,12 @@ async function runContainer(options) {
|
|
|
100
101
|
args.push('--use-api');
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
// Add --yes flag to skip confirmation prompts
|
|
105
|
+
if (yes) {
|
|
106
|
+
args.push('--yes');
|
|
107
|
+
console.log(chalk.gray(`š Debug: Adding --yes flag to Python script`));
|
|
108
|
+
}
|
|
109
|
+
|
|
103
110
|
// Handle manual setup commands if provided
|
|
104
111
|
if (setupCommands.length > 0) {
|
|
105
112
|
// Create a temporary file to store setup commands
|
|
@@ -110,6 +117,7 @@ async function runContainer(options) {
|
|
|
110
117
|
|
|
111
118
|
// Log the command being executed
|
|
112
119
|
console.log(chalk.dim(`\nExecuting: python ${args.join(' ')}`));
|
|
120
|
+
console.log(chalk.gray(`š Debug: yes parameter = ${yes}`));
|
|
113
121
|
|
|
114
122
|
// Run the Python script without spinner to avoid terminal interference
|
|
115
123
|
console.log(chalk.dim('Launching container...'));
|
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
def show_usage_examples():
|
|
2
|
+
"""Display usage examples for the script."""
|
|
3
|
+
print("Usage Examples\n")
|
|
4
|
+
|
|
5
|
+
print("š Authentication Commands")
|
|
6
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
7
|
+
print("ā gitarsenal --register # Register new account ā")
|
|
8
|
+
print("ā gitarsenal --login # Login to existing account ā")
|
|
9
|
+
print("ā gitarsenal --logout # Logout from account ā")
|
|
10
|
+
print("ā gitarsenal --user-info # Show current user information ā")
|
|
11
|
+
print("ā gitarsenal --change-password # Change password ā")
|
|
12
|
+
print("ā gitarsenal --delete-account # Delete account ā")
|
|
13
|
+
print("ā gitarsenal --store-api-key openai # Store OpenAI API key ā")
|
|
14
|
+
print("ā gitarsenal --auth # Interactive auth management ā")
|
|
15
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
16
|
+
|
|
17
|
+
print("Basic Container Creation")
|
|
18
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
19
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git ā")
|
|
20
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
21
|
+
|
|
22
|
+
print("With Setup Commands")
|
|
23
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
24
|
+
print("ā gitarsenal --gpu A100 --repo-url https://github.com/username/repo.git \\ ā")
|
|
25
|
+
print("ā --setup-commands \"pip install -r requirements.txt\" \"python setup.py install\" ā")
|
|
26
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
27
|
+
|
|
28
|
+
print("With Persistent Storage")
|
|
29
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
30
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ ā")
|
|
31
|
+
print("ā --volume-name my-persistent-volume ā")
|
|
32
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
33
|
+
|
|
34
|
+
print("With GitIngest API (default)")
|
|
35
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
36
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git ā")
|
|
37
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
38
|
+
|
|
39
|
+
print("Without GitIngest API")
|
|
40
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
41
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ ā")
|
|
42
|
+
print("ā --no-gitingest ā")
|
|
43
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
44
|
+
|
|
45
|
+
print("With Original API")
|
|
46
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
47
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ ā")
|
|
48
|
+
print("ā --use-api ā")
|
|
49
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
50
|
+
|
|
51
|
+
print("Development Mode (Skip Authentication)")
|
|
52
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
|
53
|
+
print("ā gitarsenal --skip-auth --gpu A10G --repo-url https://github.com/username/repo.git ā")
|
|
54
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
|
55
|
+
|
|
56
|
+
print("Available GPU Options:")
|
|
57
|
+
print(" T4, L4, A10G, A100-40GB, A100-80GB, L40S, H100, H200, B200")
|
|
58
|
+
print()
|
|
59
|
+
print("Authentication Behavior:")
|
|
60
|
+
print(" ⢠First time: Interactive registration/login required")
|
|
61
|
+
print(" ⢠Subsequent runs: Automatic login with stored session")
|
|
62
|
+
print(" ⢠Use --skip-auth for development (bypasses auth)")
|
|
63
|
+
print()
|
|
64
|
+
print("GPU Selection Behavior:")
|
|
65
|
+
print(" ⢠With --gpu: Uses specified GPU without prompting")
|
|
66
|
+
print(" ⢠Without --gpu: Shows interactive GPU selection menu")
|
|
67
|
+
print()
|
|
68
|
+
print("Examples:")
|
|
69
|
+
print(" # First time setup (will prompt for registration):")
|
|
70
|
+
print(" gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git")
|
|
71
|
+
print()
|
|
72
|
+
print(" # Subsequent runs (automatic login):")
|
|
73
|
+
print(" gitarsenal --repo-url https://github.com/username/repo.git")
|
|
74
|
+
print()
|
|
75
|
+
print(" # Development mode (skip authentication):")
|
|
76
|
+
print(" gitarsenal --skip-auth --repo-url https://github.com/username/repo.git")
|
|
@@ -31,6 +31,7 @@ parser.add_argument('--gpu', default='A10G', help='GPU type to use')
|
|
|
31
31
|
parser.add_argument('--repo-url', help='Repository URL')
|
|
32
32
|
parser.add_argument('--volume-name', help='Volume name')
|
|
33
33
|
parser.add_argument('--use-api', action='store_true', help='Use API to fetch setup commands')
|
|
34
|
+
parser.add_argument('--yes', action='store_true', help='Skip confirmation prompts')
|
|
34
35
|
|
|
35
36
|
# Parse only known args to avoid conflicts with other arguments
|
|
36
37
|
args, unknown = parser.parse_known_args()
|
|
@@ -520,7 +521,7 @@ class PersistentShell:
|
|
|
520
521
|
client = openai.OpenAI(api_key=api_key)
|
|
521
522
|
|
|
522
523
|
response = client.chat.completions.create(
|
|
523
|
-
model="gpt-
|
|
524
|
+
model="gpt-4.1",
|
|
524
525
|
messages=[
|
|
525
526
|
{"role": "system", "content": "You are a helpful assistant that suggests alternative commands that don't require user input."},
|
|
526
527
|
{"role": "user", "content": prompt}
|
|
@@ -573,20 +574,10 @@ class PersistentShell:
|
|
|
573
574
|
return output.strip()
|
|
574
575
|
return self.working_dir
|
|
575
576
|
|
|
576
|
-
def get_virtual_env(self):
|
|
577
|
-
"""Get the currently activated virtual environment path."""
|
|
578
|
-
return self.virtual_env_path
|
|
579
|
-
|
|
580
577
|
def is_in_venv(self):
|
|
581
578
|
"""Check if we're currently in a virtual environment."""
|
|
582
579
|
return self.virtual_env_path is not None and self.virtual_env_path != ""
|
|
583
580
|
|
|
584
|
-
def get_venv_name(self):
|
|
585
|
-
"""Get the name of the current virtual environment if active."""
|
|
586
|
-
if self.is_in_venv():
|
|
587
|
-
return os.path.basename(self.virtual_env_path)
|
|
588
|
-
return None
|
|
589
|
-
|
|
590
581
|
def exec(self, *args, **kwargs):
|
|
591
582
|
"""Compatibility method to make PersistentShell work with call_openai_for_debug."""
|
|
592
583
|
# Convert exec call to execute method
|
|
@@ -1128,7 +1119,7 @@ class CommandListManager:
|
|
|
1128
1119
|
print("š Analyzing command list for optimizations...")
|
|
1129
1120
|
|
|
1130
1121
|
response = client.chat.completions.create(
|
|
1131
|
-
model="gpt-
|
|
1122
|
+
model="gpt-4.1", # Use a more capable model for this complex task
|
|
1132
1123
|
messages=[
|
|
1133
1124
|
{"role": "system", "content": "You are a helpful assistant that analyzes and optimizes command lists."},
|
|
1134
1125
|
{"role": "user", "content": prompt}
|
|
@@ -1246,7 +1237,6 @@ class CommandListManager:
|
|
|
1246
1237
|
print(f"ā ļø Error analyzing command list: {e}")
|
|
1247
1238
|
return False
|
|
1248
1239
|
|
|
1249
|
-
|
|
1250
1240
|
# Import the fetch_modal_tokens module
|
|
1251
1241
|
# print("š Fetching tokens from proxy server...")
|
|
1252
1242
|
from fetch_modal_tokens import get_tokens
|
|
@@ -1666,13 +1656,9 @@ IMPORTANT GUIDELINES:
|
|
|
1666
1656
|
|
|
1667
1657
|
Do not provide any explanations, just the exact command to run.
|
|
1668
1658
|
"""
|
|
1669
|
-
|
|
1670
|
-
# Prepare the API request payload
|
|
1671
|
-
# print("š DEBUG: Preparing API request...")
|
|
1672
|
-
|
|
1673
|
-
# Try to use GPT-4 first, but fall back to other models if needed
|
|
1659
|
+
|
|
1674
1660
|
models_to_try = [
|
|
1675
|
-
"gpt-
|
|
1661
|
+
"gpt-4.1", # First choice: GPT-4o (most widely available)
|
|
1676
1662
|
]
|
|
1677
1663
|
|
|
1678
1664
|
# Check if we have a preferred model in environment
|
|
@@ -1680,19 +1666,12 @@ Do not provide any explanations, just the exact command to run.
|
|
|
1680
1666
|
if preferred_model:
|
|
1681
1667
|
# Insert the preferred model at the beginning of the list
|
|
1682
1668
|
models_to_try.insert(0, preferred_model)
|
|
1683
|
-
# print(f"ā
Using preferred model from environment: {preferred_model}")
|
|
1684
1669
|
|
|
1685
1670
|
# Remove duplicates while preserving order
|
|
1686
1671
|
models_to_try = list(dict.fromkeys(models_to_try))
|
|
1687
|
-
# print(f"š DEBUG: Models to try: {models_to_try}")
|
|
1688
1672
|
|
|
1689
1673
|
# Function to make the API call with a specific model
|
|
1690
1674
|
def try_api_call(model_name, retries=2, backoff_factor=1.5):
|
|
1691
|
-
# print(f"š DEBUG: Attempting API call with model: {model_name}")
|
|
1692
|
-
# print(f"š DEBUG: API key available: {'Yes' if api_key else 'No'}")
|
|
1693
|
-
# if api_key:
|
|
1694
|
-
# print(f"š DEBUG: API key length: {len(api_key)}")
|
|
1695
|
-
# print(f"š DEBUG: API key starts with: {api_key[:10]}...")
|
|
1696
1675
|
|
|
1697
1676
|
payload = {
|
|
1698
1677
|
"model": model_name,
|
|
@@ -1795,7 +1774,6 @@ Do not provide any explanations, just the exact command to run.
|
|
|
1795
1774
|
for model in models_to_try:
|
|
1796
1775
|
result, error = try_api_call(model)
|
|
1797
1776
|
if result:
|
|
1798
|
-
# print(f"ā
Successfully got response from {model}")
|
|
1799
1777
|
break
|
|
1800
1778
|
else:
|
|
1801
1779
|
print(f"ā ļø Failed to get response from {model}: {error}")
|
|
@@ -1959,7 +1937,7 @@ Provide fixes for all {len(failed_commands)} failed commands:"""
|
|
|
1959
1937
|
}
|
|
1960
1938
|
|
|
1961
1939
|
payload = {
|
|
1962
|
-
"model": "gpt-
|
|
1940
|
+
"model": "gpt-4.1", # Use a more capable model for batch analysis
|
|
1963
1941
|
"messages": [
|
|
1964
1942
|
{"role": "system", "content": "You are a debugging assistant. Analyze failed commands and provide specific fix commands. Return only the fix commands and reasons in the specified format."},
|
|
1965
1943
|
{"role": "user", "content": prompt}
|
|
@@ -2016,43 +1994,6 @@ Provide fixes for all {len(failed_commands)} failed commands:"""
|
|
|
2016
1994
|
print(f"ā Error during batch debugging: {e}")
|
|
2017
1995
|
return []
|
|
2018
1996
|
|
|
2019
|
-
def prompt_for_hf_token():
|
|
2020
|
-
"""Prompt user for Hugging Face token when needed"""
|
|
2021
|
-
# Try to use credentials manager first
|
|
2022
|
-
try:
|
|
2023
|
-
from credentials_manager import CredentialsManager
|
|
2024
|
-
credentials_manager = CredentialsManager()
|
|
2025
|
-
token = credentials_manager.get_huggingface_token()
|
|
2026
|
-
if token:
|
|
2027
|
-
return token
|
|
2028
|
-
except ImportError:
|
|
2029
|
-
# Fall back to direct input if credentials_manager is not available
|
|
2030
|
-
pass
|
|
2031
|
-
|
|
2032
|
-
# Traditional direct input method as fallback
|
|
2033
|
-
print("\n" + "="*60)
|
|
2034
|
-
print("š HUGGING FACE TOKEN REQUIRED")
|
|
2035
|
-
print("="*60)
|
|
2036
|
-
print("The training script requires a valid Hugging Face token.")
|
|
2037
|
-
print("You can get your token from: https://huggingface.co/settings/tokens")
|
|
2038
|
-
print("š Please paste your Hugging Face token below:")
|
|
2039
|
-
print(" (Your input will be hidden for security)")
|
|
2040
|
-
print("-" * 60)
|
|
2041
|
-
|
|
2042
|
-
try:
|
|
2043
|
-
token = getpass.getpass("HF Token: ").strip()
|
|
2044
|
-
if not token:
|
|
2045
|
-
print("ā No token provided.")
|
|
2046
|
-
return None
|
|
2047
|
-
print("ā
Token received successfully!")
|
|
2048
|
-
return token
|
|
2049
|
-
except KeyboardInterrupt:
|
|
2050
|
-
print("\nā Token input cancelled by user.")
|
|
2051
|
-
return None
|
|
2052
|
-
except Exception as e:
|
|
2053
|
-
print(f"ā Error getting token: {e}")
|
|
2054
|
-
return None
|
|
2055
|
-
|
|
2056
1997
|
def generate_random_password(length=16):
|
|
2057
1998
|
"""Generate a random password for SSH access"""
|
|
2058
1999
|
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
@@ -2067,11 +2008,6 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
2067
2008
|
|
|
2068
2009
|
# Use interactive mode if specified
|
|
2069
2010
|
if interactive:
|
|
2070
|
-
# If GPU type is not specified, prompt for it
|
|
2071
|
-
if not gpu_type:
|
|
2072
|
-
gpu_type = prompt_for_gpu()
|
|
2073
|
-
else:
|
|
2074
|
-
print(f"ā
Using provided GPU type: {gpu_type}")
|
|
2075
2011
|
|
|
2076
2012
|
# If repo URL is not specified, prompt for it
|
|
2077
2013
|
if not repo_url:
|
|
@@ -2748,7 +2684,6 @@ def fetch_setup_commands_from_api(repo_url):
|
|
|
2748
2684
|
print(f"ā ļø GitIngest CLI failed with exit code {result.returncode}")
|
|
2749
2685
|
print(f"ā ļø Error output: {result.stderr}")
|
|
2750
2686
|
print("Falling back to basic analysis")
|
|
2751
|
-
gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
|
|
2752
2687
|
else:
|
|
2753
2688
|
print(f"ā
GitIngest analysis completed successfully")
|
|
2754
2689
|
|
|
@@ -2832,13 +2767,13 @@ def fetch_setup_commands_from_api(repo_url):
|
|
|
2832
2767
|
print(f"š Processed GitIngest data saved to: {processed_file}")
|
|
2833
2768
|
except FileNotFoundError:
|
|
2834
2769
|
print(f"ā ļø Output file not found at {output_file}")
|
|
2835
|
-
|
|
2770
|
+
|
|
2836
2771
|
except Exception as e:
|
|
2837
2772
|
print(f"ā ļø Error reading GitIngest output: {e}")
|
|
2838
|
-
|
|
2773
|
+
|
|
2839
2774
|
else:
|
|
2840
2775
|
# Fall back to basic analysis if gitingest CLI is not available
|
|
2841
|
-
gitingest_data =
|
|
2776
|
+
gitingest_data = "{}"
|
|
2842
2777
|
|
|
2843
2778
|
# Prepare the request payload with GitIngest data
|
|
2844
2779
|
payload = {
|
|
@@ -3072,171 +3007,6 @@ def generate_fallback_commands(gitingest_data):
|
|
|
3072
3007
|
|
|
3073
3008
|
return fixed_commands
|
|
3074
3009
|
|
|
3075
|
-
def generate_basic_repo_analysis_from_url(repo_url):
|
|
3076
|
-
"""Generate basic repository analysis data from a repository URL."""
|
|
3077
|
-
import tempfile
|
|
3078
|
-
import subprocess
|
|
3079
|
-
import os
|
|
3080
|
-
import shutil
|
|
3081
|
-
|
|
3082
|
-
# Create a temporary directory for cloning
|
|
3083
|
-
temp_dir = tempfile.mkdtemp(prefix="repo_basic_analysis_")
|
|
3084
|
-
|
|
3085
|
-
try:
|
|
3086
|
-
print(f"š„ Cloning repository to {temp_dir} for basic analysis...")
|
|
3087
|
-
clone_result = subprocess.run(
|
|
3088
|
-
["git", "clone", "--depth", "1", repo_url, temp_dir],
|
|
3089
|
-
capture_output=True,
|
|
3090
|
-
text=True
|
|
3091
|
-
)
|
|
3092
|
-
|
|
3093
|
-
if clone_result.returncode != 0:
|
|
3094
|
-
print(f"ā Failed to clone repository: {clone_result.stderr}")
|
|
3095
|
-
return {
|
|
3096
|
-
"system_info": {
|
|
3097
|
-
"platform": "linux",
|
|
3098
|
-
"python_version": "3.10",
|
|
3099
|
-
"detected_language": "Unknown",
|
|
3100
|
-
"detected_technologies": [],
|
|
3101
|
-
"file_count": 0,
|
|
3102
|
-
"repo_stars": 0,
|
|
3103
|
-
"repo_forks": 0,
|
|
3104
|
-
"primary_package_manager": "Unknown",
|
|
3105
|
-
"complexity_level": "low"
|
|
3106
|
-
},
|
|
3107
|
-
"repository_analysis": {
|
|
3108
|
-
"summary": f"Repository analysis for {repo_url}",
|
|
3109
|
-
"tree": "Failed to clone repository",
|
|
3110
|
-
"content_preview": "No content available"
|
|
3111
|
-
},
|
|
3112
|
-
"success": False
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
print(f"ā
Repository cloned successfully for basic analysis")
|
|
3116
|
-
|
|
3117
|
-
# Use the existing generate_basic_repo_analysis function
|
|
3118
|
-
return generate_basic_repo_analysis(temp_dir)
|
|
3119
|
-
finally:
|
|
3120
|
-
# Clean up the temporary directory
|
|
3121
|
-
print(f"š§¹ Cleaning up temporary directory for basic analysis...")
|
|
3122
|
-
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
3123
|
-
|
|
3124
|
-
def generate_basic_repo_analysis(repo_dir):
|
|
3125
|
-
"""Generate basic repository analysis when GitIngest is not available."""
|
|
3126
|
-
import os
|
|
3127
|
-
import subprocess
|
|
3128
|
-
|
|
3129
|
-
# Detect language and technologies based on file extensions
|
|
3130
|
-
file_extensions = {}
|
|
3131
|
-
file_count = 0
|
|
3132
|
-
|
|
3133
|
-
for root, _, files in os.walk(repo_dir):
|
|
3134
|
-
for file in files:
|
|
3135
|
-
file_count += 1
|
|
3136
|
-
ext = os.path.splitext(file)[1].lower()
|
|
3137
|
-
if ext:
|
|
3138
|
-
file_extensions[ext] = file_extensions.get(ext, 0) + 1
|
|
3139
|
-
|
|
3140
|
-
# Determine primary language
|
|
3141
|
-
language_map = {
|
|
3142
|
-
'.py': 'Python',
|
|
3143
|
-
'.js': 'JavaScript',
|
|
3144
|
-
'.ts': 'TypeScript',
|
|
3145
|
-
'.jsx': 'JavaScript',
|
|
3146
|
-
'.tsx': 'TypeScript',
|
|
3147
|
-
'.java': 'Java',
|
|
3148
|
-
'.cpp': 'C++',
|
|
3149
|
-
'.c': 'C',
|
|
3150
|
-
'.go': 'Go',
|
|
3151
|
-
'.rs': 'Rust',
|
|
3152
|
-
'.rb': 'Ruby',
|
|
3153
|
-
'.php': 'PHP',
|
|
3154
|
-
'.swift': 'Swift',
|
|
3155
|
-
'.kt': 'Kotlin',
|
|
3156
|
-
'.cs': 'C#'
|
|
3157
|
-
}
|
|
3158
|
-
|
|
3159
|
-
# Count files by language
|
|
3160
|
-
language_counts = {}
|
|
3161
|
-
for ext, count in file_extensions.items():
|
|
3162
|
-
if ext in language_map:
|
|
3163
|
-
lang = language_map[ext]
|
|
3164
|
-
language_counts[lang] = language_counts.get(lang, 0) + count
|
|
3165
|
-
|
|
3166
|
-
# Determine primary language
|
|
3167
|
-
primary_language = max(language_counts.items(), key=lambda x: x[1])[0] if language_counts else "Unknown"
|
|
3168
|
-
|
|
3169
|
-
# Detect package managers
|
|
3170
|
-
package_managers = []
|
|
3171
|
-
package_files = {
|
|
3172
|
-
'requirements.txt': 'pip',
|
|
3173
|
-
'setup.py': 'pip',
|
|
3174
|
-
'pyproject.toml': 'pip',
|
|
3175
|
-
'package.json': 'npm',
|
|
3176
|
-
'yarn.lock': 'yarn',
|
|
3177
|
-
'pnpm-lock.yaml': 'pnpm',
|
|
3178
|
-
'Cargo.toml': 'cargo',
|
|
3179
|
-
'go.mod': 'go',
|
|
3180
|
-
'Gemfile': 'bundler',
|
|
3181
|
-
'pom.xml': 'maven',
|
|
3182
|
-
'build.gradle': 'gradle',
|
|
3183
|
-
'composer.json': 'composer'
|
|
3184
|
-
}
|
|
3185
|
-
|
|
3186
|
-
for file, manager in package_files.items():
|
|
3187
|
-
if os.path.exists(os.path.join(repo_dir, file)):
|
|
3188
|
-
package_managers.append(manager)
|
|
3189
|
-
|
|
3190
|
-
primary_package_manager = package_managers[0] if package_managers else "Unknown"
|
|
3191
|
-
|
|
3192
|
-
# Get README content
|
|
3193
|
-
readme_content = ""
|
|
3194
|
-
for readme_name in ['README.md', 'README', 'README.txt', 'readme.md']:
|
|
3195
|
-
readme_path = os.path.join(repo_dir, readme_name)
|
|
3196
|
-
if os.path.exists(readme_path):
|
|
3197
|
-
with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
3198
|
-
readme_content = f.read()
|
|
3199
|
-
break
|
|
3200
|
-
|
|
3201
|
-
# Try to get repository info
|
|
3202
|
-
repo_info = {}
|
|
3203
|
-
try:
|
|
3204
|
-
# Get remote origin URL
|
|
3205
|
-
cmd = ["git", "config", "--get", "remote.origin.url"]
|
|
3206
|
-
result = subprocess.run(cmd, cwd=repo_dir, capture_output=True, text=True)
|
|
3207
|
-
if result.returncode == 0:
|
|
3208
|
-
repo_info["url"] = result.stdout.strip()
|
|
3209
|
-
|
|
3210
|
-
# Get commit count as a proxy for activity
|
|
3211
|
-
cmd = ["git", "rev-list", "--count", "HEAD"]
|
|
3212
|
-
result = subprocess.run(cmd, cwd=repo_dir, capture_output=True, text=True)
|
|
3213
|
-
if result.returncode == 0:
|
|
3214
|
-
repo_info["commit_count"] = int(result.stdout.strip())
|
|
3215
|
-
except Exception:
|
|
3216
|
-
pass
|
|
3217
|
-
|
|
3218
|
-
# Build the analysis data
|
|
3219
|
-
return {
|
|
3220
|
-
"system_info": {
|
|
3221
|
-
"platform": "linux", # Assuming Linux for container environment
|
|
3222
|
-
"python_version": "3.10", # Common Python version
|
|
3223
|
-
"detected_language": primary_language,
|
|
3224
|
-
"detected_technologies": list(language_counts.keys()),
|
|
3225
|
-
"file_count": file_count,
|
|
3226
|
-
"repo_stars": repo_info.get("stars", 0),
|
|
3227
|
-
"repo_forks": repo_info.get("forks", 0),
|
|
3228
|
-
"primary_package_manager": primary_package_manager,
|
|
3229
|
-
"complexity_level": "medium" # Default assumption
|
|
3230
|
-
},
|
|
3231
|
-
"repository_analysis": {
|
|
3232
|
-
"summary": f"Repository analysis for {repo_dir}",
|
|
3233
|
-
"readme_content": readme_content[:5000] if readme_content else "No README found",
|
|
3234
|
-
"package_managers": package_managers,
|
|
3235
|
-
"file_extensions": list(file_extensions.keys())
|
|
3236
|
-
},
|
|
3237
|
-
"success": True
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
3010
|
def fix_setup_commands(commands):
|
|
3241
3011
|
"""Fix setup commands by removing placeholders and comments."""
|
|
3242
3012
|
fixed_commands = []
|
|
@@ -3746,152 +3516,6 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
|
3746
3516
|
print("ā All API endpoints failed")
|
|
3747
3517
|
return generate_fallback_commands(gitingest_data)
|
|
3748
3518
|
|
|
3749
|
-
def prompt_for_gpu():
|
|
3750
|
-
"""
|
|
3751
|
-
Prompt the user to select a GPU type from available options using arrow keys.
|
|
3752
|
-
Returns the selected GPU type.
|
|
3753
|
-
"""
|
|
3754
|
-
import sys
|
|
3755
|
-
import tty
|
|
3756
|
-
import termios
|
|
3757
|
-
|
|
3758
|
-
print("\nš§ GPU Selection Required")
|
|
3759
|
-
print("No GPU type was specified with --gpu flag.")
|
|
3760
|
-
print("Please select a GPU type for your container:")
|
|
3761
|
-
|
|
3762
|
-
# Define available GPU types and their specifications
|
|
3763
|
-
gpu_specs = {
|
|
3764
|
-
'T4': {'gpu': 'T4', 'memory': '16GB'},
|
|
3765
|
-
'L4': {'gpu': 'L4', 'memory': '24GB'},
|
|
3766
|
-
'A10G': {'gpu': 'A10G', 'memory': '24GB'},
|
|
3767
|
-
'A100-40': {'gpu': 'A100-40GB', 'memory': '40GB'},
|
|
3768
|
-
'A100-80': {'gpu': 'A100-80GB', 'memory': '80GB'},
|
|
3769
|
-
'L40S': {'gpu': 'L40S', 'memory': '48GB'},
|
|
3770
|
-
'H100': {'gpu': 'H100', 'memory': '80GB'},
|
|
3771
|
-
'H200': {'gpu': 'H200', 'memory': '141GB'},
|
|
3772
|
-
'B200': {'gpu': 'B200', 'memory': '141GB'}
|
|
3773
|
-
}
|
|
3774
|
-
|
|
3775
|
-
# Create a list of options
|
|
3776
|
-
options = list(gpu_specs.keys())
|
|
3777
|
-
selected_index = 2 # Default to A10G (index 2)
|
|
3778
|
-
|
|
3779
|
-
def get_key():
|
|
3780
|
-
"""Get a single keypress from the user."""
|
|
3781
|
-
fd = sys.stdin.fileno()
|
|
3782
|
-
old_settings = termios.tcgetattr(fd)
|
|
3783
|
-
try:
|
|
3784
|
-
tty.setraw(sys.stdin.fileno())
|
|
3785
|
-
ch = sys.stdin.read(1)
|
|
3786
|
-
if ch == '\x1b': # Escape sequence
|
|
3787
|
-
ch2 = sys.stdin.read(1)
|
|
3788
|
-
if ch2 == '[':
|
|
3789
|
-
ch3 = sys.stdin.read(1)
|
|
3790
|
-
if ch3 == 'A':
|
|
3791
|
-
return 'UP'
|
|
3792
|
-
elif ch3 == 'B':
|
|
3793
|
-
return 'DOWN'
|
|
3794
|
-
elif ch == '\r' or ch == '\n':
|
|
3795
|
-
return 'ENTER'
|
|
3796
|
-
elif ch == '\x03': # Ctrl+C
|
|
3797
|
-
return 'CTRL_C'
|
|
3798
|
-
return ch
|
|
3799
|
-
finally:
|
|
3800
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
3801
|
-
|
|
3802
|
-
def display_menu():
|
|
3803
|
-
"""Display the GPU selection menu with current selection highlighted."""
|
|
3804
|
-
print("\nš Available GPU Options:")
|
|
3805
|
-
print("āāāāāāāāāāāāāāāā¬āāāāāāāāāā")
|
|
3806
|
-
print("ā GPU Type ā VRAM ā")
|
|
3807
|
-
print("āāāāāāāāāāāāāāāā¼āāāāāāāāāā¤")
|
|
3808
|
-
|
|
3809
|
-
for i, gpu_type in enumerate(options):
|
|
3810
|
-
specs = gpu_specs[gpu_type]
|
|
3811
|
-
# Calculate proper spacing for alignment
|
|
3812
|
-
number_part = f"{i+1}."
|
|
3813
|
-
if i == selected_index:
|
|
3814
|
-
prefix = "> "
|
|
3815
|
-
suffix = " ā"
|
|
3816
|
-
else:
|
|
3817
|
-
prefix = " "
|
|
3818
|
-
suffix = ""
|
|
3819
|
-
|
|
3820
|
-
# Ensure consistent width for GPU type column
|
|
3821
|
-
gpu_display = f"{prefix}{number_part} {gpu_type}"
|
|
3822
|
-
gpu_padded = f"{gpu_display:<12}" # Fixed width for GPU column
|
|
3823
|
-
|
|
3824
|
-
print(f"ā {gpu_padded} ā {specs['memory']:<7} ā{suffix}")
|
|
3825
|
-
|
|
3826
|
-
print("āāāāāāāāāāāāāāāā“āāāāāāāāāā")
|
|
3827
|
-
print("Use ā/ā arrows to select, Enter to confirm, Ctrl+C to cancel")
|
|
3828
|
-
|
|
3829
|
-
# Clear screen and show initial menu
|
|
3830
|
-
print("\033[2J\033[H", end="") # Clear screen and move cursor to top
|
|
3831
|
-
display_menu()
|
|
3832
|
-
|
|
3833
|
-
while True:
|
|
3834
|
-
try:
|
|
3835
|
-
key = get_key()
|
|
3836
|
-
|
|
3837
|
-
if key == 'UP':
|
|
3838
|
-
selected_index = (selected_index - 1) % len(options)
|
|
3839
|
-
print("\033[2J\033[H", end="") # Clear screen
|
|
3840
|
-
display_menu()
|
|
3841
|
-
elif key == 'DOWN':
|
|
3842
|
-
selected_index = (selected_index + 1) % len(options)
|
|
3843
|
-
print("\033[2J\033[H", end="") # Clear screen
|
|
3844
|
-
display_menu()
|
|
3845
|
-
elif key == 'ENTER':
|
|
3846
|
-
selected_gpu = options[selected_index]
|
|
3847
|
-
print(f"\nā
Selected GPU: {selected_gpu}")
|
|
3848
|
-
return selected_gpu
|
|
3849
|
-
elif key == 'CTRL_C':
|
|
3850
|
-
print("\nš Selection cancelled.")
|
|
3851
|
-
sys.exit(1)
|
|
3852
|
-
|
|
3853
|
-
except KeyboardInterrupt:
|
|
3854
|
-
print("\nš Selection cancelled.")
|
|
3855
|
-
sys.exit(1)
|
|
3856
|
-
except Exception as e:
|
|
3857
|
-
print(f"\nā Error with interactive menu: {e}")
|
|
3858
|
-
print("š Falling back to simple text input...")
|
|
3859
|
-
# Fall back to simple input method
|
|
3860
|
-
try:
|
|
3861
|
-
print("\nš Available GPU Options:")
|
|
3862
|
-
for i, gpu_type in enumerate(options, 1):
|
|
3863
|
-
specs = gpu_specs[gpu_type]
|
|
3864
|
-
print(f" {i}. {gpu_type} ({specs['memory']})")
|
|
3865
|
-
print(f" Default: A10G")
|
|
3866
|
-
|
|
3867
|
-
choice = input("\nš Select GPU type (number or name, default is A10G): ").strip()
|
|
3868
|
-
if not choice:
|
|
3869
|
-
print("ā
Using default GPU: A10G")
|
|
3870
|
-
return "A10G"
|
|
3871
|
-
if choice.isdigit():
|
|
3872
|
-
index = int(choice) - 1
|
|
3873
|
-
if 0 <= index < len(options):
|
|
3874
|
-
selected = options[index]
|
|
3875
|
-
print(f"ā
Selected GPU: {selected}")
|
|
3876
|
-
return selected
|
|
3877
|
-
else:
|
|
3878
|
-
print(f"ā ļø Invalid number. Using default: A10G")
|
|
3879
|
-
return "A10G"
|
|
3880
|
-
elif choice in options:
|
|
3881
|
-
print(f"ā
Selected GPU: {choice}")
|
|
3882
|
-
return choice
|
|
3883
|
-
else:
|
|
3884
|
-
print(f"ā ļø Invalid choice '{choice}'. Using default: A10G")
|
|
3885
|
-
return "A10G"
|
|
3886
|
-
except KeyboardInterrupt:
|
|
3887
|
-
print("\nš Selection cancelled.")
|
|
3888
|
-
sys.exit(1)
|
|
3889
|
-
except Exception as fallback_error:
|
|
3890
|
-
print(f"ā Error in fallback input: {fallback_error}")
|
|
3891
|
-
print("ā
Using default GPU: A10G")
|
|
3892
|
-
return "A10G"
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
3519
|
|
|
3896
3520
|
def preprocess_commands_with_llm(setup_commands, stored_credentials, api_key=None):
|
|
3897
3521
|
"""
|
|
@@ -4235,11 +3859,6 @@ if __name__ == "__main__":
|
|
|
4235
3859
|
_handle_auth_commands(auth_manager, args)
|
|
4236
3860
|
sys.exit(0)
|
|
4237
3861
|
|
|
4238
|
-
# If --list-gpus is specified, just show GPU options and exit
|
|
4239
|
-
if args.list_gpus:
|
|
4240
|
-
prompt_for_gpu()
|
|
4241
|
-
sys.exit(0)
|
|
4242
|
-
|
|
4243
3862
|
# If no arguments or only --show-examples is provided, show usage examples
|
|
4244
3863
|
if len(sys.argv) == 1 or args.show_examples:
|
|
4245
3864
|
show_usage_examples()
|
|
@@ -4298,7 +3917,6 @@ if __name__ == "__main__":
|
|
|
4298
3917
|
else:
|
|
4299
3918
|
print("\nš No GPU type specified with --gpu flag.")
|
|
4300
3919
|
print("š Prompting for GPU selection...")
|
|
4301
|
-
gpu_type = prompt_for_gpu()
|
|
4302
3920
|
args.gpu = gpu_type
|
|
4303
3921
|
|
|
4304
3922
|
# Display configuration after GPU selection
|
|
@@ -4314,14 +3932,17 @@ if __name__ == "__main__":
|
|
|
4314
3932
|
print("Setup Commands: Auto-detect from repository")
|
|
4315
3933
|
|
|
4316
3934
|
# Confirm settings
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
3935
|
+
if not args.yes:
|
|
3936
|
+
try:
|
|
3937
|
+
proceed = input("Proceed with these settings? (Y/n): ").strip().lower()
|
|
3938
|
+
if proceed in ('n', 'no'):
|
|
3939
|
+
print("š Operation cancelled by user.")
|
|
3940
|
+
sys.exit(0)
|
|
3941
|
+
except KeyboardInterrupt:
|
|
3942
|
+
print("\nš Operation cancelled by user.")
|
|
4321
3943
|
sys.exit(0)
|
|
4322
|
-
|
|
4323
|
-
print("
|
|
4324
|
-
sys.exit(0)
|
|
3944
|
+
else:
|
|
3945
|
+
print("ā
Skipping confirmation prompt (--yes flag used)")
|
|
4325
3946
|
|
|
4326
3947
|
# Interactive mode or missing required arguments
|
|
4327
3948
|
if args.interactive or not args.repo_url or not args.volume_name:
|
|
@@ -4491,12 +4112,8 @@ if __name__ == "__main__":
|
|
|
4491
4112
|
interactive=args.interactive
|
|
4492
4113
|
)
|
|
4493
4114
|
except KeyboardInterrupt:
|
|
4494
|
-
# print("\n\nš Execution interrupted")
|
|
4495
|
-
# print("š§¹ Cleaning up resources...")
|
|
4496
4115
|
cleanup_modal_token()
|
|
4497
4116
|
sys.exit(1)
|
|
4498
4117
|
except Exception as e:
|
|
4499
|
-
# print(f"\nā Error: {e}")
|
|
4500
|
-
# print("š§¹ Cleaning up resources...")
|
|
4501
4118
|
cleanup_modal_token()
|
|
4502
4119
|
sys.exit(1)
|
|
@@ -31,6 +31,7 @@ parser.add_argument('--gpu', default='A10G', help='GPU type to use')
|
|
|
31
31
|
parser.add_argument('--repo-url', help='Repository URL')
|
|
32
32
|
parser.add_argument('--volume-name', help='Volume name')
|
|
33
33
|
parser.add_argument('--use-api', action='store_true', help='Use API to fetch setup commands')
|
|
34
|
+
parser.add_argument('--yes', action='store_true', help='Skip confirmation prompts')
|
|
34
35
|
|
|
35
36
|
# Parse only known args to avoid conflicts with other arguments
|
|
36
37
|
args, unknown = parser.parse_known_args()
|
|
@@ -520,7 +521,7 @@ class PersistentShell:
|
|
|
520
521
|
client = openai.OpenAI(api_key=api_key)
|
|
521
522
|
|
|
522
523
|
response = client.chat.completions.create(
|
|
523
|
-
model="gpt-
|
|
524
|
+
model="gpt-4.1",
|
|
524
525
|
messages=[
|
|
525
526
|
{"role": "system", "content": "You are a helpful assistant that suggests alternative commands that don't require user input."},
|
|
526
527
|
{"role": "user", "content": prompt}
|
|
@@ -573,20 +574,10 @@ class PersistentShell:
|
|
|
573
574
|
return output.strip()
|
|
574
575
|
return self.working_dir
|
|
575
576
|
|
|
576
|
-
def get_virtual_env(self):
|
|
577
|
-
"""Get the currently activated virtual environment path."""
|
|
578
|
-
return self.virtual_env_path
|
|
579
|
-
|
|
580
577
|
def is_in_venv(self):
|
|
581
578
|
"""Check if we're currently in a virtual environment."""
|
|
582
579
|
return self.virtual_env_path is not None and self.virtual_env_path != ""
|
|
583
580
|
|
|
584
|
-
def get_venv_name(self):
|
|
585
|
-
"""Get the name of the current virtual environment if active."""
|
|
586
|
-
if self.is_in_venv():
|
|
587
|
-
return os.path.basename(self.virtual_env_path)
|
|
588
|
-
return None
|
|
589
|
-
|
|
590
581
|
def exec(self, *args, **kwargs):
|
|
591
582
|
"""Compatibility method to make PersistentShell work with call_openai_for_debug."""
|
|
592
583
|
# Convert exec call to execute method
|
|
@@ -1128,7 +1119,7 @@ class CommandListManager:
|
|
|
1128
1119
|
print("š Analyzing command list for optimizations...")
|
|
1129
1120
|
|
|
1130
1121
|
response = client.chat.completions.create(
|
|
1131
|
-
model="gpt-
|
|
1122
|
+
model="gpt-4.1", # Use a more capable model for this complex task
|
|
1132
1123
|
messages=[
|
|
1133
1124
|
{"role": "system", "content": "You are a helpful assistant that analyzes and optimizes command lists."},
|
|
1134
1125
|
{"role": "user", "content": prompt}
|
|
@@ -1246,7 +1237,6 @@ class CommandListManager:
|
|
|
1246
1237
|
print(f"ā ļø Error analyzing command list: {e}")
|
|
1247
1238
|
return False
|
|
1248
1239
|
|
|
1249
|
-
|
|
1250
1240
|
# Import the fetch_modal_tokens module
|
|
1251
1241
|
# print("š Fetching tokens from proxy server...")
|
|
1252
1242
|
from fetch_modal_tokens import get_tokens
|
|
@@ -1666,13 +1656,9 @@ IMPORTANT GUIDELINES:
|
|
|
1666
1656
|
|
|
1667
1657
|
Do not provide any explanations, just the exact command to run.
|
|
1668
1658
|
"""
|
|
1669
|
-
|
|
1670
|
-
# Prepare the API request payload
|
|
1671
|
-
# print("š DEBUG: Preparing API request...")
|
|
1672
|
-
|
|
1673
|
-
# Try to use GPT-4 first, but fall back to other models if needed
|
|
1659
|
+
|
|
1674
1660
|
models_to_try = [
|
|
1675
|
-
"gpt-
|
|
1661
|
+
"gpt-4.1", # First choice: GPT-4o (most widely available)
|
|
1676
1662
|
]
|
|
1677
1663
|
|
|
1678
1664
|
# Check if we have a preferred model in environment
|
|
@@ -1680,19 +1666,12 @@ Do not provide any explanations, just the exact command to run.
|
|
|
1680
1666
|
if preferred_model:
|
|
1681
1667
|
# Insert the preferred model at the beginning of the list
|
|
1682
1668
|
models_to_try.insert(0, preferred_model)
|
|
1683
|
-
# print(f"ā
Using preferred model from environment: {preferred_model}")
|
|
1684
1669
|
|
|
1685
1670
|
# Remove duplicates while preserving order
|
|
1686
1671
|
models_to_try = list(dict.fromkeys(models_to_try))
|
|
1687
|
-
# print(f"š DEBUG: Models to try: {models_to_try}")
|
|
1688
1672
|
|
|
1689
1673
|
# Function to make the API call with a specific model
|
|
1690
1674
|
def try_api_call(model_name, retries=2, backoff_factor=1.5):
|
|
1691
|
-
# print(f"š DEBUG: Attempting API call with model: {model_name}")
|
|
1692
|
-
# print(f"š DEBUG: API key available: {'Yes' if api_key else 'No'}")
|
|
1693
|
-
# if api_key:
|
|
1694
|
-
# print(f"š DEBUG: API key length: {len(api_key)}")
|
|
1695
|
-
# print(f"š DEBUG: API key starts with: {api_key[:10]}...")
|
|
1696
1675
|
|
|
1697
1676
|
payload = {
|
|
1698
1677
|
"model": model_name,
|
|
@@ -1795,7 +1774,6 @@ Do not provide any explanations, just the exact command to run.
|
|
|
1795
1774
|
for model in models_to_try:
|
|
1796
1775
|
result, error = try_api_call(model)
|
|
1797
1776
|
if result:
|
|
1798
|
-
# print(f"ā
Successfully got response from {model}")
|
|
1799
1777
|
break
|
|
1800
1778
|
else:
|
|
1801
1779
|
print(f"ā ļø Failed to get response from {model}: {error}")
|
|
@@ -1959,7 +1937,7 @@ Provide fixes for all {len(failed_commands)} failed commands:"""
|
|
|
1959
1937
|
}
|
|
1960
1938
|
|
|
1961
1939
|
payload = {
|
|
1962
|
-
"model": "gpt-
|
|
1940
|
+
"model": "gpt-4.1", # Use a more capable model for batch analysis
|
|
1963
1941
|
"messages": [
|
|
1964
1942
|
{"role": "system", "content": "You are a debugging assistant. Analyze failed commands and provide specific fix commands. Return only the fix commands and reasons in the specified format."},
|
|
1965
1943
|
{"role": "user", "content": prompt}
|
|
@@ -2016,43 +1994,6 @@ Provide fixes for all {len(failed_commands)} failed commands:"""
|
|
|
2016
1994
|
print(f"ā Error during batch debugging: {e}")
|
|
2017
1995
|
return []
|
|
2018
1996
|
|
|
2019
|
-
def prompt_for_hf_token():
|
|
2020
|
-
"""Prompt user for Hugging Face token when needed"""
|
|
2021
|
-
# Try to use credentials manager first
|
|
2022
|
-
try:
|
|
2023
|
-
from credentials_manager import CredentialsManager
|
|
2024
|
-
credentials_manager = CredentialsManager()
|
|
2025
|
-
token = credentials_manager.get_huggingface_token()
|
|
2026
|
-
if token:
|
|
2027
|
-
return token
|
|
2028
|
-
except ImportError:
|
|
2029
|
-
# Fall back to direct input if credentials_manager is not available
|
|
2030
|
-
pass
|
|
2031
|
-
|
|
2032
|
-
# Traditional direct input method as fallback
|
|
2033
|
-
print("\n" + "="*60)
|
|
2034
|
-
print("š HUGGING FACE TOKEN REQUIRED")
|
|
2035
|
-
print("="*60)
|
|
2036
|
-
print("The training script requires a valid Hugging Face token.")
|
|
2037
|
-
print("You can get your token from: https://huggingface.co/settings/tokens")
|
|
2038
|
-
print("š Please paste your Hugging Face token below:")
|
|
2039
|
-
print(" (Your input will be hidden for security)")
|
|
2040
|
-
print("-" * 60)
|
|
2041
|
-
|
|
2042
|
-
try:
|
|
2043
|
-
token = getpass.getpass("HF Token: ").strip()
|
|
2044
|
-
if not token:
|
|
2045
|
-
print("ā No token provided.")
|
|
2046
|
-
return None
|
|
2047
|
-
print("ā
Token received successfully!")
|
|
2048
|
-
return token
|
|
2049
|
-
except KeyboardInterrupt:
|
|
2050
|
-
print("\nā Token input cancelled by user.")
|
|
2051
|
-
return None
|
|
2052
|
-
except Exception as e:
|
|
2053
|
-
print(f"ā Error getting token: {e}")
|
|
2054
|
-
return None
|
|
2055
|
-
|
|
2056
1997
|
def generate_random_password(length=16):
|
|
2057
1998
|
"""Generate a random password for SSH access"""
|
|
2058
1999
|
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
@@ -2067,11 +2008,6 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
|
2067
2008
|
|
|
2068
2009
|
# Use interactive mode if specified
|
|
2069
2010
|
if interactive:
|
|
2070
|
-
# If GPU type is not specified, prompt for it
|
|
2071
|
-
if not gpu_type:
|
|
2072
|
-
gpu_type = prompt_for_gpu()
|
|
2073
|
-
else:
|
|
2074
|
-
print(f"ā
Using provided GPU type: {gpu_type}")
|
|
2075
2011
|
|
|
2076
2012
|
# If repo URL is not specified, prompt for it
|
|
2077
2013
|
if not repo_url:
|
|
@@ -2748,7 +2684,6 @@ def fetch_setup_commands_from_api(repo_url):
|
|
|
2748
2684
|
print(f"ā ļø GitIngest CLI failed with exit code {result.returncode}")
|
|
2749
2685
|
print(f"ā ļø Error output: {result.stderr}")
|
|
2750
2686
|
print("Falling back to basic analysis")
|
|
2751
|
-
gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
|
|
2752
2687
|
else:
|
|
2753
2688
|
print(f"ā
GitIngest analysis completed successfully")
|
|
2754
2689
|
|
|
@@ -2832,13 +2767,13 @@ def fetch_setup_commands_from_api(repo_url):
|
|
|
2832
2767
|
print(f"š Processed GitIngest data saved to: {processed_file}")
|
|
2833
2768
|
except FileNotFoundError:
|
|
2834
2769
|
print(f"ā ļø Output file not found at {output_file}")
|
|
2835
|
-
|
|
2770
|
+
|
|
2836
2771
|
except Exception as e:
|
|
2837
2772
|
print(f"ā ļø Error reading GitIngest output: {e}")
|
|
2838
|
-
|
|
2773
|
+
|
|
2839
2774
|
else:
|
|
2840
2775
|
# Fall back to basic analysis if gitingest CLI is not available
|
|
2841
|
-
gitingest_data =
|
|
2776
|
+
gitingest_data = "{}"
|
|
2842
2777
|
|
|
2843
2778
|
# Prepare the request payload with GitIngest data
|
|
2844
2779
|
payload = {
|
|
@@ -3072,171 +3007,6 @@ def generate_fallback_commands(gitingest_data):
|
|
|
3072
3007
|
|
|
3073
3008
|
return fixed_commands
|
|
3074
3009
|
|
|
3075
|
-
def generate_basic_repo_analysis_from_url(repo_url):
|
|
3076
|
-
"""Generate basic repository analysis data from a repository URL."""
|
|
3077
|
-
import tempfile
|
|
3078
|
-
import subprocess
|
|
3079
|
-
import os
|
|
3080
|
-
import shutil
|
|
3081
|
-
|
|
3082
|
-
# Create a temporary directory for cloning
|
|
3083
|
-
temp_dir = tempfile.mkdtemp(prefix="repo_basic_analysis_")
|
|
3084
|
-
|
|
3085
|
-
try:
|
|
3086
|
-
print(f"š„ Cloning repository to {temp_dir} for basic analysis...")
|
|
3087
|
-
clone_result = subprocess.run(
|
|
3088
|
-
["git", "clone", "--depth", "1", repo_url, temp_dir],
|
|
3089
|
-
capture_output=True,
|
|
3090
|
-
text=True
|
|
3091
|
-
)
|
|
3092
|
-
|
|
3093
|
-
if clone_result.returncode != 0:
|
|
3094
|
-
print(f"ā Failed to clone repository: {clone_result.stderr}")
|
|
3095
|
-
return {
|
|
3096
|
-
"system_info": {
|
|
3097
|
-
"platform": "linux",
|
|
3098
|
-
"python_version": "3.10",
|
|
3099
|
-
"detected_language": "Unknown",
|
|
3100
|
-
"detected_technologies": [],
|
|
3101
|
-
"file_count": 0,
|
|
3102
|
-
"repo_stars": 0,
|
|
3103
|
-
"repo_forks": 0,
|
|
3104
|
-
"primary_package_manager": "Unknown",
|
|
3105
|
-
"complexity_level": "low"
|
|
3106
|
-
},
|
|
3107
|
-
"repository_analysis": {
|
|
3108
|
-
"summary": f"Repository analysis for {repo_url}",
|
|
3109
|
-
"tree": "Failed to clone repository",
|
|
3110
|
-
"content_preview": "No content available"
|
|
3111
|
-
},
|
|
3112
|
-
"success": False
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
print(f"ā
Repository cloned successfully for basic analysis")
|
|
3116
|
-
|
|
3117
|
-
# Use the existing generate_basic_repo_analysis function
|
|
3118
|
-
return generate_basic_repo_analysis(temp_dir)
|
|
3119
|
-
finally:
|
|
3120
|
-
# Clean up the temporary directory
|
|
3121
|
-
print(f"š§¹ Cleaning up temporary directory for basic analysis...")
|
|
3122
|
-
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
3123
|
-
|
|
3124
|
-
def generate_basic_repo_analysis(repo_dir):
|
|
3125
|
-
"""Generate basic repository analysis when GitIngest is not available."""
|
|
3126
|
-
import os
|
|
3127
|
-
import subprocess
|
|
3128
|
-
|
|
3129
|
-
# Detect language and technologies based on file extensions
|
|
3130
|
-
file_extensions = {}
|
|
3131
|
-
file_count = 0
|
|
3132
|
-
|
|
3133
|
-
for root, _, files in os.walk(repo_dir):
|
|
3134
|
-
for file in files:
|
|
3135
|
-
file_count += 1
|
|
3136
|
-
ext = os.path.splitext(file)[1].lower()
|
|
3137
|
-
if ext:
|
|
3138
|
-
file_extensions[ext] = file_extensions.get(ext, 0) + 1
|
|
3139
|
-
|
|
3140
|
-
# Determine primary language
|
|
3141
|
-
language_map = {
|
|
3142
|
-
'.py': 'Python',
|
|
3143
|
-
'.js': 'JavaScript',
|
|
3144
|
-
'.ts': 'TypeScript',
|
|
3145
|
-
'.jsx': 'JavaScript',
|
|
3146
|
-
'.tsx': 'TypeScript',
|
|
3147
|
-
'.java': 'Java',
|
|
3148
|
-
'.cpp': 'C++',
|
|
3149
|
-
'.c': 'C',
|
|
3150
|
-
'.go': 'Go',
|
|
3151
|
-
'.rs': 'Rust',
|
|
3152
|
-
'.rb': 'Ruby',
|
|
3153
|
-
'.php': 'PHP',
|
|
3154
|
-
'.swift': 'Swift',
|
|
3155
|
-
'.kt': 'Kotlin',
|
|
3156
|
-
'.cs': 'C#'
|
|
3157
|
-
}
|
|
3158
|
-
|
|
3159
|
-
# Count files by language
|
|
3160
|
-
language_counts = {}
|
|
3161
|
-
for ext, count in file_extensions.items():
|
|
3162
|
-
if ext in language_map:
|
|
3163
|
-
lang = language_map[ext]
|
|
3164
|
-
language_counts[lang] = language_counts.get(lang, 0) + count
|
|
3165
|
-
|
|
3166
|
-
# Determine primary language
|
|
3167
|
-
primary_language = max(language_counts.items(), key=lambda x: x[1])[0] if language_counts else "Unknown"
|
|
3168
|
-
|
|
3169
|
-
# Detect package managers
|
|
3170
|
-
package_managers = []
|
|
3171
|
-
package_files = {
|
|
3172
|
-
'requirements.txt': 'pip',
|
|
3173
|
-
'setup.py': 'pip',
|
|
3174
|
-
'pyproject.toml': 'pip',
|
|
3175
|
-
'package.json': 'npm',
|
|
3176
|
-
'yarn.lock': 'yarn',
|
|
3177
|
-
'pnpm-lock.yaml': 'pnpm',
|
|
3178
|
-
'Cargo.toml': 'cargo',
|
|
3179
|
-
'go.mod': 'go',
|
|
3180
|
-
'Gemfile': 'bundler',
|
|
3181
|
-
'pom.xml': 'maven',
|
|
3182
|
-
'build.gradle': 'gradle',
|
|
3183
|
-
'composer.json': 'composer'
|
|
3184
|
-
}
|
|
3185
|
-
|
|
3186
|
-
for file, manager in package_files.items():
|
|
3187
|
-
if os.path.exists(os.path.join(repo_dir, file)):
|
|
3188
|
-
package_managers.append(manager)
|
|
3189
|
-
|
|
3190
|
-
primary_package_manager = package_managers[0] if package_managers else "Unknown"
|
|
3191
|
-
|
|
3192
|
-
# Get README content
|
|
3193
|
-
readme_content = ""
|
|
3194
|
-
for readme_name in ['README.md', 'README', 'README.txt', 'readme.md']:
|
|
3195
|
-
readme_path = os.path.join(repo_dir, readme_name)
|
|
3196
|
-
if os.path.exists(readme_path):
|
|
3197
|
-
with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
3198
|
-
readme_content = f.read()
|
|
3199
|
-
break
|
|
3200
|
-
|
|
3201
|
-
# Try to get repository info
|
|
3202
|
-
repo_info = {}
|
|
3203
|
-
try:
|
|
3204
|
-
# Get remote origin URL
|
|
3205
|
-
cmd = ["git", "config", "--get", "remote.origin.url"]
|
|
3206
|
-
result = subprocess.run(cmd, cwd=repo_dir, capture_output=True, text=True)
|
|
3207
|
-
if result.returncode == 0:
|
|
3208
|
-
repo_info["url"] = result.stdout.strip()
|
|
3209
|
-
|
|
3210
|
-
# Get commit count as a proxy for activity
|
|
3211
|
-
cmd = ["git", "rev-list", "--count", "HEAD"]
|
|
3212
|
-
result = subprocess.run(cmd, cwd=repo_dir, capture_output=True, text=True)
|
|
3213
|
-
if result.returncode == 0:
|
|
3214
|
-
repo_info["commit_count"] = int(result.stdout.strip())
|
|
3215
|
-
except Exception:
|
|
3216
|
-
pass
|
|
3217
|
-
|
|
3218
|
-
# Build the analysis data
|
|
3219
|
-
return {
|
|
3220
|
-
"system_info": {
|
|
3221
|
-
"platform": "linux", # Assuming Linux for container environment
|
|
3222
|
-
"python_version": "3.10", # Common Python version
|
|
3223
|
-
"detected_language": primary_language,
|
|
3224
|
-
"detected_technologies": list(language_counts.keys()),
|
|
3225
|
-
"file_count": file_count,
|
|
3226
|
-
"repo_stars": repo_info.get("stars", 0),
|
|
3227
|
-
"repo_forks": repo_info.get("forks", 0),
|
|
3228
|
-
"primary_package_manager": primary_package_manager,
|
|
3229
|
-
"complexity_level": "medium" # Default assumption
|
|
3230
|
-
},
|
|
3231
|
-
"repository_analysis": {
|
|
3232
|
-
"summary": f"Repository analysis for {repo_dir}",
|
|
3233
|
-
"readme_content": readme_content[:5000] if readme_content else "No README found",
|
|
3234
|
-
"package_managers": package_managers,
|
|
3235
|
-
"file_extensions": list(file_extensions.keys())
|
|
3236
|
-
},
|
|
3237
|
-
"success": True
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
3010
|
def fix_setup_commands(commands):
|
|
3241
3011
|
"""Fix setup commands by removing placeholders and comments."""
|
|
3242
3012
|
fixed_commands = []
|
|
@@ -3746,152 +3516,6 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
|
3746
3516
|
print("ā All API endpoints failed")
|
|
3747
3517
|
return generate_fallback_commands(gitingest_data)
|
|
3748
3518
|
|
|
3749
|
-
def prompt_for_gpu():
|
|
3750
|
-
"""
|
|
3751
|
-
Prompt the user to select a GPU type from available options using arrow keys.
|
|
3752
|
-
Returns the selected GPU type.
|
|
3753
|
-
"""
|
|
3754
|
-
import sys
|
|
3755
|
-
import tty
|
|
3756
|
-
import termios
|
|
3757
|
-
|
|
3758
|
-
print("\nš§ GPU Selection Required")
|
|
3759
|
-
print("No GPU type was specified with --gpu flag.")
|
|
3760
|
-
print("Please select a GPU type for your container:")
|
|
3761
|
-
|
|
3762
|
-
# Define available GPU types and their specifications
|
|
3763
|
-
gpu_specs = {
|
|
3764
|
-
'T4': {'gpu': 'T4', 'memory': '16GB'},
|
|
3765
|
-
'L4': {'gpu': 'L4', 'memory': '24GB'},
|
|
3766
|
-
'A10G': {'gpu': 'A10G', 'memory': '24GB'},
|
|
3767
|
-
'A100-40': {'gpu': 'A100-40GB', 'memory': '40GB'},
|
|
3768
|
-
'A100-80': {'gpu': 'A100-80GB', 'memory': '80GB'},
|
|
3769
|
-
'L40S': {'gpu': 'L40S', 'memory': '48GB'},
|
|
3770
|
-
'H100': {'gpu': 'H100', 'memory': '80GB'},
|
|
3771
|
-
'H200': {'gpu': 'H200', 'memory': '141GB'},
|
|
3772
|
-
'B200': {'gpu': 'B200', 'memory': '141GB'}
|
|
3773
|
-
}
|
|
3774
|
-
|
|
3775
|
-
# Create a list of options
|
|
3776
|
-
options = list(gpu_specs.keys())
|
|
3777
|
-
selected_index = 2 # Default to A10G (index 2)
|
|
3778
|
-
|
|
3779
|
-
def get_key():
|
|
3780
|
-
"""Get a single keypress from the user."""
|
|
3781
|
-
fd = sys.stdin.fileno()
|
|
3782
|
-
old_settings = termios.tcgetattr(fd)
|
|
3783
|
-
try:
|
|
3784
|
-
tty.setraw(sys.stdin.fileno())
|
|
3785
|
-
ch = sys.stdin.read(1)
|
|
3786
|
-
if ch == '\x1b': # Escape sequence
|
|
3787
|
-
ch2 = sys.stdin.read(1)
|
|
3788
|
-
if ch2 == '[':
|
|
3789
|
-
ch3 = sys.stdin.read(1)
|
|
3790
|
-
if ch3 == 'A':
|
|
3791
|
-
return 'UP'
|
|
3792
|
-
elif ch3 == 'B':
|
|
3793
|
-
return 'DOWN'
|
|
3794
|
-
elif ch == '\r' or ch == '\n':
|
|
3795
|
-
return 'ENTER'
|
|
3796
|
-
elif ch == '\x03': # Ctrl+C
|
|
3797
|
-
return 'CTRL_C'
|
|
3798
|
-
return ch
|
|
3799
|
-
finally:
|
|
3800
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
3801
|
-
|
|
3802
|
-
def display_menu():
|
|
3803
|
-
"""Display the GPU selection menu with current selection highlighted."""
|
|
3804
|
-
print("\nš Available GPU Options:")
|
|
3805
|
-
print("āāāāāāāāāāāāāāāā¬āāāāāāāāāā")
|
|
3806
|
-
print("ā GPU Type ā VRAM ā")
|
|
3807
|
-
print("āāāāāāāāāāāāāāāā¼āāāāāāāāāā¤")
|
|
3808
|
-
|
|
3809
|
-
for i, gpu_type in enumerate(options):
|
|
3810
|
-
specs = gpu_specs[gpu_type]
|
|
3811
|
-
# Calculate proper spacing for alignment
|
|
3812
|
-
number_part = f"{i+1}."
|
|
3813
|
-
if i == selected_index:
|
|
3814
|
-
prefix = "> "
|
|
3815
|
-
suffix = " ā"
|
|
3816
|
-
else:
|
|
3817
|
-
prefix = " "
|
|
3818
|
-
suffix = ""
|
|
3819
|
-
|
|
3820
|
-
# Ensure consistent width for GPU type column
|
|
3821
|
-
gpu_display = f"{prefix}{number_part} {gpu_type}"
|
|
3822
|
-
gpu_padded = f"{gpu_display:<12}" # Fixed width for GPU column
|
|
3823
|
-
|
|
3824
|
-
print(f"ā {gpu_padded} ā {specs['memory']:<7} ā{suffix}")
|
|
3825
|
-
|
|
3826
|
-
print("āāāāāāāāāāāāāāāā“āāāāāāāāāā")
|
|
3827
|
-
print("Use ā/ā arrows to select, Enter to confirm, Ctrl+C to cancel")
|
|
3828
|
-
|
|
3829
|
-
# Clear screen and show initial menu
|
|
3830
|
-
print("\033[2J\033[H", end="") # Clear screen and move cursor to top
|
|
3831
|
-
display_menu()
|
|
3832
|
-
|
|
3833
|
-
while True:
|
|
3834
|
-
try:
|
|
3835
|
-
key = get_key()
|
|
3836
|
-
|
|
3837
|
-
if key == 'UP':
|
|
3838
|
-
selected_index = (selected_index - 1) % len(options)
|
|
3839
|
-
print("\033[2J\033[H", end="") # Clear screen
|
|
3840
|
-
display_menu()
|
|
3841
|
-
elif key == 'DOWN':
|
|
3842
|
-
selected_index = (selected_index + 1) % len(options)
|
|
3843
|
-
print("\033[2J\033[H", end="") # Clear screen
|
|
3844
|
-
display_menu()
|
|
3845
|
-
elif key == 'ENTER':
|
|
3846
|
-
selected_gpu = options[selected_index]
|
|
3847
|
-
print(f"\nā
Selected GPU: {selected_gpu}")
|
|
3848
|
-
return selected_gpu
|
|
3849
|
-
elif key == 'CTRL_C':
|
|
3850
|
-
print("\nš Selection cancelled.")
|
|
3851
|
-
sys.exit(1)
|
|
3852
|
-
|
|
3853
|
-
except KeyboardInterrupt:
|
|
3854
|
-
print("\nš Selection cancelled.")
|
|
3855
|
-
sys.exit(1)
|
|
3856
|
-
except Exception as e:
|
|
3857
|
-
print(f"\nā Error with interactive menu: {e}")
|
|
3858
|
-
print("š Falling back to simple text input...")
|
|
3859
|
-
# Fall back to simple input method
|
|
3860
|
-
try:
|
|
3861
|
-
print("\nš Available GPU Options:")
|
|
3862
|
-
for i, gpu_type in enumerate(options, 1):
|
|
3863
|
-
specs = gpu_specs[gpu_type]
|
|
3864
|
-
print(f" {i}. {gpu_type} ({specs['memory']})")
|
|
3865
|
-
print(f" Default: A10G")
|
|
3866
|
-
|
|
3867
|
-
choice = input("\nš Select GPU type (number or name, default is A10G): ").strip()
|
|
3868
|
-
if not choice:
|
|
3869
|
-
print("ā
Using default GPU: A10G")
|
|
3870
|
-
return "A10G"
|
|
3871
|
-
if choice.isdigit():
|
|
3872
|
-
index = int(choice) - 1
|
|
3873
|
-
if 0 <= index < len(options):
|
|
3874
|
-
selected = options[index]
|
|
3875
|
-
print(f"ā
Selected GPU: {selected}")
|
|
3876
|
-
return selected
|
|
3877
|
-
else:
|
|
3878
|
-
print(f"ā ļø Invalid number. Using default: A10G")
|
|
3879
|
-
return "A10G"
|
|
3880
|
-
elif choice in options:
|
|
3881
|
-
print(f"ā
Selected GPU: {choice}")
|
|
3882
|
-
return choice
|
|
3883
|
-
else:
|
|
3884
|
-
print(f"ā ļø Invalid choice '{choice}'. Using default: A10G")
|
|
3885
|
-
return "A10G"
|
|
3886
|
-
except KeyboardInterrupt:
|
|
3887
|
-
print("\nš Selection cancelled.")
|
|
3888
|
-
sys.exit(1)
|
|
3889
|
-
except Exception as fallback_error:
|
|
3890
|
-
print(f"ā Error in fallback input: {fallback_error}")
|
|
3891
|
-
print("ā
Using default GPU: A10G")
|
|
3892
|
-
return "A10G"
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
3519
|
|
|
3896
3520
|
def preprocess_commands_with_llm(setup_commands, stored_credentials, api_key=None):
|
|
3897
3521
|
"""
|
|
@@ -4198,7 +3822,6 @@ if __name__ == "__main__":
|
|
|
4198
3822
|
parser = argparse.ArgumentParser()
|
|
4199
3823
|
parser.add_argument('--gpu', type=str, help='GPU type (e.g., A10G, T4, A100-80GB). If not provided, will prompt for GPU selection.')
|
|
4200
3824
|
parser.add_argument('--repo-url', type=str, help='Repository URL to clone')
|
|
4201
|
-
parser.add_argument('--repo-name', type=str, help='Repository name override')
|
|
4202
3825
|
parser.add_argument('--setup-commands', type=str, nargs='+', help='Setup commands to run (deprecated)')
|
|
4203
3826
|
parser.add_argument('--setup-commands-json', type=str, help='Setup commands as JSON array')
|
|
4204
3827
|
parser.add_argument('--commands-file', type=str, help='Path to file containing setup commands (one per line)')
|
|
@@ -4235,11 +3858,6 @@ if __name__ == "__main__":
|
|
|
4235
3858
|
_handle_auth_commands(auth_manager, args)
|
|
4236
3859
|
sys.exit(0)
|
|
4237
3860
|
|
|
4238
|
-
# If --list-gpus is specified, just show GPU options and exit
|
|
4239
|
-
if args.list_gpus:
|
|
4240
|
-
prompt_for_gpu()
|
|
4241
|
-
sys.exit(0)
|
|
4242
|
-
|
|
4243
3861
|
# If no arguments or only --show-examples is provided, show usage examples
|
|
4244
3862
|
if len(sys.argv) == 1 or args.show_examples:
|
|
4245
3863
|
show_usage_examples()
|
|
@@ -4298,7 +3916,6 @@ if __name__ == "__main__":
|
|
|
4298
3916
|
else:
|
|
4299
3917
|
print("\nš No GPU type specified with --gpu flag.")
|
|
4300
3918
|
print("š Prompting for GPU selection...")
|
|
4301
|
-
gpu_type = prompt_for_gpu()
|
|
4302
3919
|
args.gpu = gpu_type
|
|
4303
3920
|
|
|
4304
3921
|
# Display configuration after GPU selection
|
|
@@ -4314,14 +3931,17 @@ if __name__ == "__main__":
|
|
|
4314
3931
|
print("Setup Commands: Auto-detect from repository")
|
|
4315
3932
|
|
|
4316
3933
|
# Confirm settings
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
3934
|
+
if not args.yes:
|
|
3935
|
+
try:
|
|
3936
|
+
proceed = input("Proceed with these settings? (Y/n): ").strip().lower()
|
|
3937
|
+
if proceed in ('n', 'no'):
|
|
3938
|
+
print("š Operation cancelled by user.")
|
|
3939
|
+
sys.exit(0)
|
|
3940
|
+
except KeyboardInterrupt:
|
|
3941
|
+
print("\nš Operation cancelled by user.")
|
|
4321
3942
|
sys.exit(0)
|
|
4322
|
-
|
|
4323
|
-
print("
|
|
4324
|
-
sys.exit(0)
|
|
3943
|
+
else:
|
|
3944
|
+
print("ā
Skipping confirmation prompt (--yes flag used)")
|
|
4325
3945
|
|
|
4326
3946
|
# Interactive mode or missing required arguments
|
|
4327
3947
|
if args.interactive or not args.repo_url or not args.volume_name:
|
|
Binary file
|
package/eval_repos.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|