gitarsenal-cli 1.8.3 โ 1.8.5
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/activate_venv.sh +4 -0
- package/package.json +1 -1
- package/python/__pycache__/auth_manager.cpython-313.pyc +0 -0
- package/python/auth_manager.py +485 -0
- package/python/debug_delete.py +167 -0
- package/python/gitarsenal.py +188 -0
- package/python/gitarsenal_keys.py +43 -55
- package/python/test_modalSandboxScript.py +358 -89
- package/scripts/postinstall.js +150 -39
- package/test_modalSandboxScript.py +358 -89
@@ -16,6 +16,13 @@ import signal
|
|
16
16
|
from pathlib import Path
|
17
17
|
import modal
|
18
18
|
|
19
|
+
# Import authentication manager
|
20
|
+
try:
|
21
|
+
from auth_manager import AuthManager
|
22
|
+
except ImportError:
|
23
|
+
print("โ Authentication module not found. Please ensure auth_manager.py is in the same directory.")
|
24
|
+
sys.exit(1)
|
25
|
+
|
19
26
|
# Parse command-line arguments
|
20
27
|
parser = argparse.ArgumentParser()
|
21
28
|
parser.add_argument('--proxy-url', help='URL of the proxy server')
|
@@ -1616,7 +1623,6 @@ Consider the current directory, system information, directory contents, and avai
|
|
1616
1623
|
IMPORTANT GUIDELINES:
|
1617
1624
|
1. For any commands that might ask for yes/no confirmation, use the appropriate non-interactive flag:
|
1618
1625
|
- For apt/apt-get: use -y or --yes
|
1619
|
-
- For pip: use --no-input
|
1620
1626
|
- For rm: use -f or --force
|
1621
1627
|
|
1622
1628
|
2. If the error indicates a file is not found:
|
@@ -3326,6 +3332,18 @@ def show_usage_examples():
|
|
3326
3332
|
"""Display usage examples for the script."""
|
3327
3333
|
print("Usage Examples\n")
|
3328
3334
|
|
3335
|
+
print("๐ Authentication Commands")
|
3336
|
+
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
3337
|
+
print("โ gitarsenal --register # Register new account โ")
|
3338
|
+
print("โ gitarsenal --login # Login to existing account โ")
|
3339
|
+
print("โ gitarsenal --logout # Logout from account โ")
|
3340
|
+
print("โ gitarsenal --user-info # Show current user information โ")
|
3341
|
+
print("โ gitarsenal --change-password # Change password โ")
|
3342
|
+
print("โ gitarsenal --delete-account # Delete account โ")
|
3343
|
+
print("โ gitarsenal --store-api-key openai # Store OpenAI API key โ")
|
3344
|
+
print("โ gitarsenal --auth # Interactive auth management โ")
|
3345
|
+
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n")
|
3346
|
+
|
3329
3347
|
print("Basic Container Creation")
|
3330
3348
|
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
3331
3349
|
print("โ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git โ")
|
@@ -3360,19 +3378,32 @@ def show_usage_examples():
|
|
3360
3378
|
print("โ --use-api โ")
|
3361
3379
|
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n")
|
3362
3380
|
|
3381
|
+
print("Development Mode (Skip Authentication)")
|
3382
|
+
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
3383
|
+
print("โ gitarsenal --skip-auth --gpu A10G --repo-url https://github.com/username/repo.git โ")
|
3384
|
+
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n")
|
3385
|
+
|
3363
3386
|
print("Available GPU Options:")
|
3364
3387
|
print(" T4, L4, A10G, A100-40GB, A100-80GB, L40S, H100, H200, B200")
|
3365
3388
|
print()
|
3389
|
+
print("Authentication Behavior:")
|
3390
|
+
print(" โข First time: Interactive registration/login required")
|
3391
|
+
print(" โข Subsequent runs: Automatic login with stored session")
|
3392
|
+
print(" โข Use --skip-auth for development (bypasses auth)")
|
3393
|
+
print()
|
3366
3394
|
print("GPU Selection Behavior:")
|
3367
3395
|
print(" โข With --gpu: Uses specified GPU without prompting")
|
3368
3396
|
print(" โข Without --gpu: Shows interactive GPU selection menu")
|
3369
3397
|
print()
|
3370
3398
|
print("Examples:")
|
3371
|
-
print(" #
|
3399
|
+
print(" # First time setup (will prompt for registration):")
|
3372
3400
|
print(" gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git")
|
3373
3401
|
print()
|
3374
|
-
print(" #
|
3402
|
+
print(" # Subsequent runs (automatic login):")
|
3375
3403
|
print(" gitarsenal --repo-url https://github.com/username/repo.git")
|
3404
|
+
print()
|
3405
|
+
print(" # Development mode (skip authentication):")
|
3406
|
+
print(" gitarsenal --skip-auth --repo-url https://github.com/username/repo.git")
|
3376
3407
|
|
3377
3408
|
def make_api_request_with_retry(url, payload, max_retries=2, timeout=180):
|
3378
3409
|
"""Make an API request with retry mechanism."""
|
@@ -3860,6 +3891,304 @@ def prompt_for_gpu():
|
|
3860
3891
|
print("โ
Using default GPU: A10G")
|
3861
3892
|
return "A10G"
|
3862
3893
|
|
3894
|
+
|
3895
|
+
|
3896
|
+
def preprocess_commands_with_llm(setup_commands, stored_credentials, api_key=None):
|
3897
|
+
"""
|
3898
|
+
Use LLM to preprocess setup commands and inject available credentials.
|
3899
|
+
|
3900
|
+
Args:
|
3901
|
+
setup_commands: List of setup commands
|
3902
|
+
stored_credentials: Dictionary of stored credentials
|
3903
|
+
api_key: OpenAI API key for LLM calls
|
3904
|
+
|
3905
|
+
Returns:
|
3906
|
+
List of processed commands with credentials injected
|
3907
|
+
"""
|
3908
|
+
if not setup_commands or not stored_credentials:
|
3909
|
+
return setup_commands
|
3910
|
+
|
3911
|
+
try:
|
3912
|
+
# Create context for the LLM
|
3913
|
+
credentials_info = "\n".join([f"- {key}: {value[:8]}..." for key, value in stored_credentials.items()])
|
3914
|
+
|
3915
|
+
prompt = f"""
|
3916
|
+
You are a command preprocessing assistant. Your task is to modify setup commands to use available credentials and make them non-interactive.
|
3917
|
+
|
3918
|
+
AVAILABLE CREDENTIALS:
|
3919
|
+
{credentials_info}
|
3920
|
+
|
3921
|
+
ORIGINAL COMMANDS:
|
3922
|
+
{chr(10).join([f"{i+1}. {cmd}" for i, cmd in enumerate(setup_commands)])}
|
3923
|
+
|
3924
|
+
INSTRUCTIONS:
|
3925
|
+
1. Replace any authentication commands with token-based versions using available credentials
|
3926
|
+
2. Make all commands non-interactive (add --yes, --no-input, -y flags where needed)
|
3927
|
+
3. Use environment variables or direct token injection where appropriate
|
3928
|
+
4. Skip commands that cannot be made non-interactive due to missing credentials
|
3929
|
+
5. Add any necessary environment variable exports
|
3930
|
+
|
3931
|
+
Return the modified commands as a JSON array of strings. If a command should be skipped, prefix it with "# SKIPPED: ".
|
3932
|
+
|
3933
|
+
Example transformations:
|
3934
|
+
- "huggingface-cli login" โ "huggingface-cli login --token $HUGGINGFACE_TOKEN"
|
3935
|
+
- "npm install" โ "npm install --yes"
|
3936
|
+
|
3937
|
+
Return only the JSON array, no other text.
|
3938
|
+
"""
|
3939
|
+
|
3940
|
+
if not api_key:
|
3941
|
+
print("โ ๏ธ No OpenAI API key available for command preprocessing")
|
3942
|
+
return setup_commands
|
3943
|
+
|
3944
|
+
# Call OpenAI API
|
3945
|
+
import openai
|
3946
|
+
client = openai.OpenAI(api_key=api_key)
|
3947
|
+
|
3948
|
+
response = client.chat.completions.create(
|
3949
|
+
model="gpt-3.5-turbo",
|
3950
|
+
messages=[
|
3951
|
+
{"role": "system", "content": "You are a command preprocessing assistant that modifies setup commands to use available credentials and make them non-interactive."},
|
3952
|
+
{"role": "user", "content": prompt}
|
3953
|
+
],
|
3954
|
+
temperature=0.1,
|
3955
|
+
max_tokens=2000
|
3956
|
+
)
|
3957
|
+
|
3958
|
+
result = response.choices[0].message.content.strip()
|
3959
|
+
|
3960
|
+
# Debug: Print the raw response
|
3961
|
+
print(f"๐ LLM Response: {result[:200]}...")
|
3962
|
+
|
3963
|
+
# Parse the JSON response
|
3964
|
+
import json
|
3965
|
+
try:
|
3966
|
+
processed_commands = json.loads(result)
|
3967
|
+
if isinstance(processed_commands, list):
|
3968
|
+
print(f"๐ง LLM preprocessed {len(processed_commands)} commands")
|
3969
|
+
for i, cmd in enumerate(processed_commands):
|
3970
|
+
if cmd != setup_commands[i]:
|
3971
|
+
print(f" {i+1}. {setup_commands[i]} โ {cmd}")
|
3972
|
+
return processed_commands
|
3973
|
+
else:
|
3974
|
+
print("โ ๏ธ LLM returned invalid format, using fallback preprocessing")
|
3975
|
+
return fallback_preprocess_commands(setup_commands, stored_credentials)
|
3976
|
+
except json.JSONDecodeError as e:
|
3977
|
+
print(f"โ ๏ธ Failed to parse LLM response: {e}")
|
3978
|
+
print("๐ Using fallback preprocessing...")
|
3979
|
+
return fallback_preprocess_commands(setup_commands, stored_credentials)
|
3980
|
+
|
3981
|
+
except Exception as e:
|
3982
|
+
print(f"โ ๏ธ LLM preprocessing failed: {e}")
|
3983
|
+
print("๐ Using fallback preprocessing...")
|
3984
|
+
return fallback_preprocess_commands(setup_commands, stored_credentials)
|
3985
|
+
|
3986
|
+
def fallback_preprocess_commands(setup_commands, stored_credentials):
|
3987
|
+
"""
|
3988
|
+
Fallback preprocessing function that manually handles common credential injection patterns.
|
3989
|
+
|
3990
|
+
Args:
|
3991
|
+
setup_commands: List of setup commands
|
3992
|
+
stored_credentials: Dictionary of stored credentials
|
3993
|
+
|
3994
|
+
Returns:
|
3995
|
+
List of processed commands with credentials injected
|
3996
|
+
"""
|
3997
|
+
if not setup_commands or not stored_credentials:
|
3998
|
+
return setup_commands
|
3999
|
+
|
4000
|
+
processed_commands = []
|
4001
|
+
|
4002
|
+
for i, command in enumerate(setup_commands):
|
4003
|
+
processed_command = command
|
4004
|
+
|
4005
|
+
# Handle Hugging Face login
|
4006
|
+
if 'huggingface-cli login' in command and '--token' not in command:
|
4007
|
+
if 'HUGGINGFACE_TOKEN' in stored_credentials:
|
4008
|
+
processed_command = f"huggingface-cli login --token $HUGGINGFACE_TOKEN"
|
4009
|
+
print(f"๐ง Fallback: Injected HF token into command {i+1}")
|
4010
|
+
else:
|
4011
|
+
processed_command = f"# SKIPPED: {command} (no HF token available)"
|
4012
|
+
print(f"๐ง Fallback: Skipped command {i+1} (no HF token)")
|
4013
|
+
|
4014
|
+
# Handle OpenAI API key
|
4015
|
+
elif 'openai' in command.lower() and 'api_key' not in command.lower():
|
4016
|
+
if 'OPENAI_API_KEY' in stored_credentials:
|
4017
|
+
processed_command = f"export OPENAI_API_KEY=$OPENAI_API_KEY && {command}"
|
4018
|
+
print(f"๐ง Fallback: Added OpenAI API key export to command {i+1}")
|
4019
|
+
|
4020
|
+
# Handle npm install
|
4021
|
+
elif 'npm install' in command and '--yes' not in command and '--no-interactive' not in command:
|
4022
|
+
processed_command = command.replace('npm install', 'npm install --yes')
|
4023
|
+
print(f"๐ง Fallback: Made npm install non-interactive in command {i+1}")
|
4024
|
+
|
4025
|
+
# Handle git clone
|
4026
|
+
elif command.strip().startswith('git clone') and '--depth 1' not in command:
|
4027
|
+
processed_command = command.replace('git clone', 'git clone --depth 1')
|
4028
|
+
print(f"๐ง Fallback: Made git clone non-interactive in command {i+1}")
|
4029
|
+
|
4030
|
+
# Handle apt-get install
|
4031
|
+
elif 'apt-get install' in command and '-y' not in command:
|
4032
|
+
processed_command = command.replace('apt-get install', 'apt-get install -y')
|
4033
|
+
print(f"๐ง Fallback: Made apt-get install non-interactive in command {i+1}")
|
4034
|
+
|
4035
|
+
processed_commands.append(processed_command)
|
4036
|
+
|
4037
|
+
print(f"๐ง Fallback preprocessing completed: {len(processed_commands)} commands")
|
4038
|
+
return processed_commands
|
4039
|
+
|
4040
|
+
def _check_authentication(auth_manager):
|
4041
|
+
"""Check if user is authenticated, prompt for login if not"""
|
4042
|
+
if auth_manager.is_authenticated():
|
4043
|
+
user = auth_manager.get_current_user()
|
4044
|
+
print(f"โ
Authenticated as: {user['username']}")
|
4045
|
+
return True
|
4046
|
+
|
4047
|
+
print("\n๐ Authentication required")
|
4048
|
+
return auth_manager.interactive_auth_flow()
|
4049
|
+
|
4050
|
+
def _handle_auth_commands(auth_manager, args):
|
4051
|
+
"""Handle authentication-related commands"""
|
4052
|
+
if args.login:
|
4053
|
+
print("\n๐ LOGIN")
|
4054
|
+
username = input("Username: ").strip()
|
4055
|
+
password = getpass.getpass("Password: ").strip()
|
4056
|
+
if auth_manager.login_user(username, password):
|
4057
|
+
print("โ
Login successful!")
|
4058
|
+
else:
|
4059
|
+
print("โ Login failed.")
|
4060
|
+
|
4061
|
+
elif args.register:
|
4062
|
+
print("\n๐ REGISTRATION")
|
4063
|
+
username = input("Username (min 3 characters): ").strip()
|
4064
|
+
email = input("Email: ").strip()
|
4065
|
+
password = getpass.getpass("Password (min 8 characters): ").strip()
|
4066
|
+
confirm_password = getpass.getpass("Confirm password: ").strip()
|
4067
|
+
|
4068
|
+
if password != confirm_password:
|
4069
|
+
print("โ Passwords do not match.")
|
4070
|
+
return
|
4071
|
+
|
4072
|
+
if auth_manager.register_user(username, email, password):
|
4073
|
+
print("โ
Registration successful!")
|
4074
|
+
# Auto-login after registration
|
4075
|
+
if auth_manager.login_user(username, password):
|
4076
|
+
print("โ
Auto-login successful!")
|
4077
|
+
else:
|
4078
|
+
print("โ Registration failed.")
|
4079
|
+
|
4080
|
+
elif args.logout:
|
4081
|
+
auth_manager.logout_user()
|
4082
|
+
|
4083
|
+
elif args.user_info:
|
4084
|
+
auth_manager.show_user_info()
|
4085
|
+
|
4086
|
+
elif args.change_password:
|
4087
|
+
if not auth_manager.is_authenticated():
|
4088
|
+
print("โ Not logged in. Please login first.")
|
4089
|
+
return
|
4090
|
+
|
4091
|
+
current_password = getpass.getpass("Current password: ").strip()
|
4092
|
+
new_password = getpass.getpass("New password (min 8 characters): ").strip()
|
4093
|
+
confirm_password = getpass.getpass("Confirm new password: ").strip()
|
4094
|
+
|
4095
|
+
if new_password != confirm_password:
|
4096
|
+
print("โ New passwords do not match.")
|
4097
|
+
return
|
4098
|
+
|
4099
|
+
if auth_manager.change_password(current_password, new_password):
|
4100
|
+
print("โ
Password changed successfully!")
|
4101
|
+
else:
|
4102
|
+
print("โ Failed to change password.")
|
4103
|
+
|
4104
|
+
elif args.delete_account:
|
4105
|
+
if not auth_manager.is_authenticated():
|
4106
|
+
print("โ Not logged in. Please login first.")
|
4107
|
+
return
|
4108
|
+
|
4109
|
+
password = getpass.getpass("Enter your password to confirm deletion: ").strip()
|
4110
|
+
if auth_manager.delete_account(password):
|
4111
|
+
print("โ
Account deleted successfully!")
|
4112
|
+
else:
|
4113
|
+
print("โ Failed to delete account.")
|
4114
|
+
|
4115
|
+
elif args.store_api_key:
|
4116
|
+
if not auth_manager.is_authenticated():
|
4117
|
+
print("โ Not logged in. Please login first.")
|
4118
|
+
return
|
4119
|
+
|
4120
|
+
service = args.store_api_key
|
4121
|
+
api_key = getpass.getpass(f"Enter {service} API key: ").strip()
|
4122
|
+
|
4123
|
+
if auth_manager.store_api_key(service, api_key):
|
4124
|
+
print(f"โ
{service} API key stored successfully!")
|
4125
|
+
else:
|
4126
|
+
print(f"โ Failed to store {service} API key.")
|
4127
|
+
|
4128
|
+
elif args.auth:
|
4129
|
+
# Interactive authentication management
|
4130
|
+
while True:
|
4131
|
+
print("\n" + "="*60)
|
4132
|
+
print("๐ AUTHENTICATION MANAGEMENT")
|
4133
|
+
print("="*60)
|
4134
|
+
print("1. Login")
|
4135
|
+
print("2. Register")
|
4136
|
+
print("3. Show user info")
|
4137
|
+
print("4. Change password")
|
4138
|
+
print("5. Store API key")
|
4139
|
+
print("6. Delete account")
|
4140
|
+
print("7. Logout")
|
4141
|
+
print("8. Exit")
|
4142
|
+
|
4143
|
+
choice = input("\nSelect an option (1-8): ").strip()
|
4144
|
+
|
4145
|
+
if choice == "1":
|
4146
|
+
username = input("Username: ").strip()
|
4147
|
+
password = getpass.getpass("Password: ").strip()
|
4148
|
+
auth_manager.login_user(username, password)
|
4149
|
+
elif choice == "2":
|
4150
|
+
username = input("Username (min 3 characters): ").strip()
|
4151
|
+
email = input("Email: ").strip()
|
4152
|
+
password = getpass.getpass("Password (min 8 characters): ").strip()
|
4153
|
+
confirm_password = getpass.getpass("Confirm password: ").strip()
|
4154
|
+
if password == confirm_password:
|
4155
|
+
auth_manager.register_user(username, email, password)
|
4156
|
+
else:
|
4157
|
+
print("โ Passwords do not match.")
|
4158
|
+
elif choice == "3":
|
4159
|
+
auth_manager.show_user_info()
|
4160
|
+
elif choice == "4":
|
4161
|
+
if auth_manager.is_authenticated():
|
4162
|
+
current_password = getpass.getpass("Current password: ").strip()
|
4163
|
+
new_password = getpass.getpass("New password (min 8 characters): ").strip()
|
4164
|
+
confirm_password = getpass.getpass("Confirm new password: ").strip()
|
4165
|
+
if new_password == confirm_password:
|
4166
|
+
auth_manager.change_password(current_password, new_password)
|
4167
|
+
else:
|
4168
|
+
print("โ New passwords do not match.")
|
4169
|
+
else:
|
4170
|
+
print("โ Not logged in.")
|
4171
|
+
elif choice == "5":
|
4172
|
+
if auth_manager.is_authenticated():
|
4173
|
+
service = input("Service name (e.g., openai, modal): ").strip()
|
4174
|
+
api_key = getpass.getpass(f"Enter {service} API key: ").strip()
|
4175
|
+
auth_manager.store_api_key(service, api_key)
|
4176
|
+
else:
|
4177
|
+
print("โ Not logged in.")
|
4178
|
+
elif choice == "6":
|
4179
|
+
if auth_manager.is_authenticated():
|
4180
|
+
password = getpass.getpass("Enter your password to confirm deletion: ").strip()
|
4181
|
+
auth_manager.delete_account(password)
|
4182
|
+
else:
|
4183
|
+
print("โ Not logged in.")
|
4184
|
+
elif choice == "7":
|
4185
|
+
auth_manager.logout_user()
|
4186
|
+
elif choice == "8":
|
4187
|
+
print("๐ Goodbye!")
|
4188
|
+
break
|
4189
|
+
else:
|
4190
|
+
print("โ Invalid option. Please try again.")
|
4191
|
+
|
3863
4192
|
# Replace the existing GPU argument parsing in the main section
|
3864
4193
|
if __name__ == "__main__":
|
3865
4194
|
# Parse command line arguments when script is run directly
|
@@ -3885,8 +4214,27 @@ if __name__ == "__main__":
|
|
3885
4214
|
parser.add_argument('--list-gpus', action='store_true', help='List available GPU types with their specifications')
|
3886
4215
|
parser.add_argument('--interactive', action='store_true', help='Run in interactive mode with prompts')
|
3887
4216
|
|
4217
|
+
# Authentication-related arguments
|
4218
|
+
parser.add_argument('--auth', action='store_true', help='Manage authentication (login, register, logout)')
|
4219
|
+
parser.add_argument('--login', action='store_true', help='Login to GitArsenal')
|
4220
|
+
parser.add_argument('--register', action='store_true', help='Register new account')
|
4221
|
+
parser.add_argument('--logout', action='store_true', help='Logout from GitArsenal')
|
4222
|
+
parser.add_argument('--user-info', action='store_true', help='Show current user information')
|
4223
|
+
parser.add_argument('--change-password', action='store_true', help='Change password')
|
4224
|
+
parser.add_argument('--delete-account', action='store_true', help='Delete account')
|
4225
|
+
parser.add_argument('--store-api-key', type=str, help='Store API key for a service (e.g., openai, modal)')
|
4226
|
+
parser.add_argument('--skip-auth', action='store_true', help='Skip authentication check (for development)')
|
4227
|
+
|
3888
4228
|
args = parser.parse_args()
|
3889
4229
|
|
4230
|
+
# Initialize authentication manager
|
4231
|
+
auth_manager = AuthManager()
|
4232
|
+
|
4233
|
+
# Handle authentication-related commands
|
4234
|
+
if args.auth or args.login or args.register or args.logout or args.user_info or args.change_password or args.delete_account or args.store_api_key:
|
4235
|
+
_handle_auth_commands(auth_manager, args)
|
4236
|
+
sys.exit(0)
|
4237
|
+
|
3890
4238
|
# If --list-gpus is specified, just show GPU options and exit
|
3891
4239
|
if args.list_gpus:
|
3892
4240
|
prompt_for_gpu()
|
@@ -3897,6 +4245,13 @@ if __name__ == "__main__":
|
|
3897
4245
|
show_usage_examples()
|
3898
4246
|
sys.exit(0)
|
3899
4247
|
|
4248
|
+
# Check authentication (unless skipped for development)
|
4249
|
+
if not args.skip_auth:
|
4250
|
+
if not _check_authentication(auth_manager):
|
4251
|
+
print("\nโ Authentication required. Please login or register first.")
|
4252
|
+
print("Use --login to login or --register to create an account.")
|
4253
|
+
sys.exit(1)
|
4254
|
+
|
3900
4255
|
# Check for dependencies
|
3901
4256
|
print("โ Checking dependencies...")
|
3902
4257
|
print("--- Dependency Check ---")
|
@@ -4145,89 +4500,3 @@ if __name__ == "__main__":
|
|
4145
4500
|
# print("๐งน Cleaning up resources...")
|
4146
4501
|
cleanup_modal_token()
|
4147
4502
|
sys.exit(1)
|
4148
|
-
|
4149
|
-
def preprocess_commands_with_llm(setup_commands, stored_credentials, api_key=None):
|
4150
|
-
"""
|
4151
|
-
Use LLM to preprocess setup commands and inject available credentials.
|
4152
|
-
|
4153
|
-
Args:
|
4154
|
-
setup_commands: List of setup commands
|
4155
|
-
stored_credentials: Dictionary of stored credentials
|
4156
|
-
api_key: OpenAI API key for LLM calls
|
4157
|
-
|
4158
|
-
Returns:
|
4159
|
-
List of processed commands with credentials injected
|
4160
|
-
"""
|
4161
|
-
if not setup_commands or not stored_credentials:
|
4162
|
-
return setup_commands
|
4163
|
-
|
4164
|
-
try:
|
4165
|
-
# Create context for the LLM
|
4166
|
-
credentials_info = "\n".join([f"- {key}: {value[:8]}..." for key, value in stored_credentials.items()])
|
4167
|
-
|
4168
|
-
prompt = f"""
|
4169
|
-
You are a command preprocessing assistant. Your task is to modify setup commands to use available credentials and make them non-interactive.
|
4170
|
-
|
4171
|
-
AVAILABLE CREDENTIALS:
|
4172
|
-
{credentials_info}
|
4173
|
-
|
4174
|
-
ORIGINAL COMMANDS:
|
4175
|
-
{chr(10).join([f"{i+1}. {cmd}" for i, cmd in enumerate(setup_commands)])}
|
4176
|
-
|
4177
|
-
INSTRUCTIONS:
|
4178
|
-
1. Replace any authentication commands with token-based versions using available credentials
|
4179
|
-
2. Make all commands non-interactive (add --yes, --no-input, -y flags where needed)
|
4180
|
-
3. Use environment variables or direct token injection where appropriate
|
4181
|
-
4. Skip commands that cannot be made non-interactive due to missing credentials
|
4182
|
-
5. Add any necessary environment variable exports
|
4183
|
-
|
4184
|
-
Return the modified commands as a JSON array of strings. If a command should be skipped, prefix it with "# SKIPPED: ".
|
4185
|
-
|
4186
|
-
Example transformations:
|
4187
|
-
- "huggingface-cli login" โ "huggingface-cli login --token $HUGGINGFACE_TOKEN"
|
4188
|
-
- "npm install" โ "npm install --yes"
|
4189
|
-
- "pip install package" โ "pip install package --no-input"
|
4190
|
-
|
4191
|
-
Return only the JSON array, no other text.
|
4192
|
-
"""
|
4193
|
-
|
4194
|
-
if not api_key:
|
4195
|
-
print("โ ๏ธ No OpenAI API key available for command preprocessing")
|
4196
|
-
return setup_commands
|
4197
|
-
|
4198
|
-
# Call OpenAI API
|
4199
|
-
import openai
|
4200
|
-
client = openai.OpenAI(api_key=api_key)
|
4201
|
-
|
4202
|
-
response = client.chat.completions.create(
|
4203
|
-
model="gpt-3.5-turbo",
|
4204
|
-
messages=[
|
4205
|
-
{"role": "system", "content": "You are a command preprocessing assistant that modifies setup commands to use available credentials and make them non-interactive."},
|
4206
|
-
{"role": "user", "content": prompt}
|
4207
|
-
],
|
4208
|
-
temperature=0.1,
|
4209
|
-
max_tokens=2000
|
4210
|
-
)
|
4211
|
-
|
4212
|
-
result = response.choices[0].message.content.strip()
|
4213
|
-
|
4214
|
-
# Parse the JSON response
|
4215
|
-
import json
|
4216
|
-
try:
|
4217
|
-
processed_commands = json.loads(result)
|
4218
|
-
if isinstance(processed_commands, list):
|
4219
|
-
print(f"๐ง LLM preprocessed {len(processed_commands)} commands")
|
4220
|
-
for i, cmd in enumerate(processed_commands):
|
4221
|
-
if cmd != setup_commands[i]:
|
4222
|
-
print(f" {i+1}. {setup_commands[i]} โ {cmd}")
|
4223
|
-
return processed_commands
|
4224
|
-
else:
|
4225
|
-
print("โ ๏ธ LLM returned invalid format, using original commands")
|
4226
|
-
return setup_commands
|
4227
|
-
except json.JSONDecodeError:
|
4228
|
-
print("โ ๏ธ Failed to parse LLM response, using original commands")
|
4229
|
-
return setup_commands
|
4230
|
-
|
4231
|
-
except Exception as e:
|
4232
|
-
print(f"โ ๏ธ LLM preprocessing failed: {e}")
|
4233
|
-
return setup_commands
|