gitarsenal-cli 1.3.4 โ†’ 1.3.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitarsenal-cli",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -36,10 +36,10 @@ if args.proxy_api_key:
36
36
  # First, try to fetch tokens from the proxy server
37
37
  try:
38
38
  # Import the fetch_modal_tokens module
39
- print("๐Ÿ”„ Fetching Modal tokens from proxy server...")
39
+ print("๐Ÿ”„ Fetching tokens from proxy server...")
40
40
  from fetch_modal_tokens import get_tokens
41
41
  token_id, token_secret = get_tokens()
42
- print(f"โœ… Modal tokens fetched successfully")
42
+ print(f"โœ… Tokens fetched successfully")
43
43
 
44
44
  # Explicitly set the environment variables again to be sure
45
45
  os.environ["MODAL_TOKEN_ID"] = token_id
@@ -116,16 +116,16 @@ except Exception as e:
116
116
 
117
117
  # Print debug info
118
118
  print(f"๐Ÿ” DEBUG: Checking environment variables")
119
- print(f"๐Ÿ” MODAL_TOKEN_ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
120
- print(f"๐Ÿ” MODAL_TOKEN_SECRET exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
121
- print(f"๐Ÿ” MODAL_TOKEN exists: {'Yes' if os.environ.get('MODAL_TOKEN') else 'No'}")
119
+ print(f"๐Ÿ” Token ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
120
+ print(f"๐Ÿ” Token secret exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
121
+ print(f"๐Ÿ” Token exists: {'Yes' if os.environ.get('MODAL_TOKEN') else 'No'}")
122
122
  if os.environ.get('MODAL_TOKEN_ID'):
123
- print(f"๐Ÿ” MODAL_TOKEN_ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
123
+ print(f"๐Ÿ” Token ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
124
124
  if os.environ.get('MODAL_TOKEN_SECRET'):
125
- print(f"๐Ÿ” MODAL_TOKEN_SECRET length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
125
+ print(f"๐Ÿ” Token secret length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
126
126
  if os.environ.get('MODAL_TOKEN'):
127
- print(f"๐Ÿ” MODAL_TOKEN length: {len(os.environ.get('MODAL_TOKEN'))}")
128
- print(f"โœ… Modal token setup completed")
127
+ print(f"๐Ÿ” Token length: {len(os.environ.get('MODAL_TOKEN'))}")
128
+ print(f"โœ… Token setup completed")
129
129
 
130
130
  # Import modal after token setup
131
131
  import modal
@@ -604,12 +604,12 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
604
604
  try:
605
605
  # This will raise an exception if not authenticated
606
606
  modal.config.get_current_workspace_name()
607
- print("โœ… Modal authentication verified")
607
+ print("โœ… Authentication verified")
608
608
  except modal.exception.AuthError:
609
609
  print("\n" + "="*80)
610
- print("๐Ÿ”‘ MODAL AUTHENTICATION REQUIRED")
610
+ print("๐Ÿ”‘ AUTHENTICATION REQUIRED")
611
611
  print("="*80)
612
- print("GitArsenal requires Modal authentication to create cloud environments.")
612
+ print("GitArsenal requires authentication to create cloud environments.")
613
613
 
614
614
  # Try to get token from credentials manager
615
615
  modal_token = None
@@ -703,7 +703,7 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
703
703
  gpu_type = 'A10G'
704
704
 
705
705
  gpu_spec = gpu_configs[gpu_type]
706
- print(f"๐Ÿš€ Creating Modal sandbox with {gpu_spec['gpu']} GPU ({gpu_spec['memory']}GB VRAM)")
706
+ print(f"๐Ÿš€ Creating sandbox with {gpu_spec['gpu']} GPU ({gpu_spec['memory']}GB VRAM)")
707
707
 
708
708
  # Initialize uv_path variable
709
709
  uv_path = ""
@@ -738,7 +738,7 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
738
738
  # Enable output for image building
739
739
  with modal.enable_output():
740
740
  # Create a Modal app and sandbox
741
- print(f"๐Ÿš€ Creating Modal sandbox with GPU: {gpu_type.lower()} (App: {app_name})...")
741
+ print(f"๐Ÿš€ Creating sandbox with GPU: {gpu_type.lower()} (App: {app_name})...")
742
742
  # Always use lookup with create_if_missing=True to properly initialize the app
743
743
  app = modal.App.lookup(app_name, create_if_missing=True)
744
744
  print(f"Created app: {app_name}")
@@ -947,7 +947,7 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
947
947
  return str(maybe_bytes)
948
948
 
949
949
  # Skip the persistent shell approach for now due to async stream complexity
950
- print("๐Ÿ” Modal's async streams require complex async handling")
950
+ print("๐Ÿ” async streams require complex async handling")
951
951
  print("๐Ÿ”„ Switching to individual command execution approach for reliability...")
952
952
 
953
953
  # Initialize state tracking variables
@@ -2013,7 +2013,7 @@ cd "{current_dir}"
2013
2013
  f.write(container_id)
2014
2014
 
2015
2015
  # Print connection instructions
2016
- print(f"โœ… Modal sandbox created successfully!")
2016
+ print(f"โœ… Sandbox created successfully!")
2017
2017
  print(f"๐Ÿ“‹ Sandbox ID: {sandbox_id}")
2018
2018
  print(f"๐Ÿ“‹ Container ID: {container_id}")
2019
2019
  if volume:
@@ -2246,12 +2246,12 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2246
2246
  print("๐Ÿ” DEBUG: Checking environment variables")
2247
2247
  modal_token_id = os.environ.get("MODAL_TOKEN_ID")
2248
2248
  modal_token = os.environ.get("MODAL_TOKEN")
2249
- print(f"๐Ÿ” MODAL_TOKEN_ID exists: {'Yes' if modal_token_id else 'No'}")
2250
- print(f"๐Ÿ” MODAL_TOKEN exists: {'Yes' if modal_token else 'No'}")
2249
+ print(f"๐Ÿ” token exists: {'Yes' if modal_token_id else 'No'}")
2250
+ print(f"๐Ÿ” token exists: {'Yes' if modal_token else 'No'}")
2251
2251
  if modal_token_id:
2252
- print(f"๐Ÿ” MODAL_TOKEN_ID length: {len(modal_token_id)}")
2252
+ print(f"๐Ÿ” token length: {len(modal_token_id)}")
2253
2253
  if modal_token:
2254
- print(f"๐Ÿ” MODAL_TOKEN length: {len(modal_token)}")
2254
+ print(f"๐Ÿ” token length: {len(modal_token)}")
2255
2255
 
2256
2256
  # Try to access Modal token to check authentication
2257
2257
  try:
@@ -2262,13 +2262,13 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2262
2262
  # Try to get from MODAL_TOKEN
2263
2263
  modal_token = os.environ.get("MODAL_TOKEN")
2264
2264
  if modal_token:
2265
- print("โœ… Found token in MODAL_TOKEN environment variable")
2265
+ print("โœ… Found token in environment variable")
2266
2266
  os.environ["MODAL_TOKEN_ID"] = modal_token
2267
2267
  modal_token_id = modal_token
2268
- print(f"โœ… Set MODAL_TOKEN_ID from MODAL_TOKEN (length: {len(modal_token)})")
2268
+ print(f"โœ… Set token (length: {len(modal_token)})")
2269
2269
 
2270
2270
  if modal_token_id:
2271
- print(f"โœ… Modal token found (length: {len(modal_token_id)})")
2271
+ print(f"โœ… token found (length: {len(modal_token_id)})")
2272
2272
 
2273
2273
  # Use the comprehensive fix_modal_token script
2274
2274
  try:
@@ -2289,11 +2289,11 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2289
2289
  if result.stderr:
2290
2290
  print(f"Error: {result.stderr}")
2291
2291
 
2292
- print(f"โœ… Modal token setup completed")
2292
+ print(f"โœ… token setup completed")
2293
2293
  except Exception as e:
2294
2294
  print(f"โš ๏ธ Error running fix_modal_token.py: {e}")
2295
2295
  else:
2296
- print("โŒ No Modal token found in environment variables")
2296
+ print("โŒ No token found in environment variables")
2297
2297
  # Try to get from file as a last resort
2298
2298
  try:
2299
2299
  home_dir = os.path.expanduser("~")
@@ -2312,7 +2312,7 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2312
2312
  else:
2313
2313
  print("โŒ Token file does not contain token_id")
2314
2314
  else:
2315
- print("โŒ Modal token file not found")
2315
+ print("โŒ token file not found")
2316
2316
  except Exception as e:
2317
2317
  print(f"โŒ Error loading token from file: {e}")
2318
2318
 
@@ -2326,9 +2326,9 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2326
2326
  modal_token_id = os.environ.get("MODAL_TOKEN_ID")
2327
2327
  modal_token = os.environ.get("MODAL_TOKEN")
2328
2328
  if modal_token_id:
2329
- print(f"๐Ÿ”„ Using MODAL_TOKEN_ID from environment (length: {len(modal_token_id)})")
2329
+ print(f"๐Ÿ”„ Using token from environment (length: {len(modal_token_id)})")
2330
2330
  elif modal_token:
2331
- print(f"๐Ÿ”„ Using MODAL_TOKEN from environment (length: {len(modal_token)})")
2331
+ print(f"๐Ÿ”„ Using token from environment (length: {len(modal_token)})")
2332
2332
  os.environ["MODAL_TOKEN_ID"] = modal_token
2333
2333
  modal_token_id = modal_token
2334
2334
  else:
@@ -2338,7 +2338,7 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2338
2338
  # Set it in both environment variables
2339
2339
  os.environ["MODAL_TOKEN_ID"] = modal_token_id
2340
2340
  os.environ["MODAL_TOKEN"] = modal_token_id
2341
- print("โœ… Set both MODAL_TOKEN_ID and MODAL_TOKEN environment variables")
2341
+ print("โœ… Set both token and id environment variables")
2342
2342
  except Exception as e:
2343
2343
  print(f"โš ๏ธ Error checking Modal authentication: {e}")
2344
2344
  print("Continuing anyway, but Modal operations may fail")
@@ -2364,7 +2364,7 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2364
2364
  gpu_type = 'A10G'
2365
2365
 
2366
2366
  gpu_spec = gpu_configs[gpu_type]
2367
- print(f"๐Ÿš€ Creating Modal SSH container with {gpu_spec['gpu']} GPU ({gpu_spec['memory']}GB VRAM)")
2367
+ print(f"๐Ÿš€ Creating SSH container with {gpu_spec['gpu']} GPU ({gpu_spec['memory']}GB VRAM)")
2368
2368
 
2369
2369
  # Generate or use provided SSH password
2370
2370
  if not ssh_password:
@@ -2400,16 +2400,16 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2400
2400
  # Print debug info for authentication
2401
2401
  print("๐Ÿ” Modal authentication debug info:")
2402
2402
  modal_token = os.environ.get("MODAL_TOKEN_ID")
2403
- print(f" - MODAL_TOKEN_ID in env: {'Yes' if modal_token else 'No'}")
2403
+ print(f" - token in env: {'Yes' if modal_token else 'No'}")
2404
2404
  print(f" - Token length: {len(modal_token) if modal_token else 'N/A'}")
2405
2405
 
2406
2406
  # Verify we can create a Modal app
2407
2407
  try:
2408
- print("๐Ÿ” Testing Modal app creation...")
2408
+ print("๐Ÿ” Testing app creation...")
2409
2409
  app = modal.App(app_name)
2410
- print("โœ… Created Modal app successfully")
2410
+ print("โœ… Created app successfully")
2411
2411
  except Exception as e:
2412
- print(f"โŒ Error creating Modal app: {e}")
2412
+ print(f"โŒ Error creating app: {e}")
2413
2413
  return None
2414
2414
 
2415
2415
  # Create SSH-enabled image
@@ -3302,33 +3302,33 @@ Respond with only 'NAVIGATE' if navigation makes sense, or 'SKIP' if it's redund
3302
3302
  return None
3303
3303
 
3304
3304
  def cleanup_modal_token():
3305
- """Delete Modal token files and environment variables after SSH container is started"""
3306
- print("๐Ÿงน Cleaning up Modal token for security...")
3305
+ """Delete token files and environment variables after SSH container is started"""
3306
+ print("๐Ÿงน Cleaning up tokens for security...")
3307
3307
 
3308
3308
  try:
3309
3309
  # Remove token from environment variables
3310
3310
  if "MODAL_TOKEN_ID" in os.environ:
3311
3311
  del os.environ["MODAL_TOKEN_ID"]
3312
- print("โœ… Removed MODAL_TOKEN_ID from environment")
3312
+ print("โœ… Removed token ID from environment")
3313
3313
 
3314
3314
  if "MODAL_TOKEN" in os.environ:
3315
3315
  del os.environ["MODAL_TOKEN"]
3316
- print("โœ… Removed MODAL_TOKEN from environment")
3316
+ print("โœ… Removed token from environment")
3317
3317
 
3318
3318
  if "MODAL_TOKEN_SECRET" in os.environ:
3319
3319
  del os.environ["MODAL_TOKEN_SECRET"]
3320
- print("โœ… Removed MODAL_TOKEN_SECRET from environment")
3320
+ print("โœ… Removed token secret from environment")
3321
3321
 
3322
3322
  # Delete ~/.modal.toml file
3323
3323
  home_dir = os.path.expanduser("~")
3324
3324
  modal_toml = os.path.join(home_dir, ".modal.toml")
3325
3325
  if os.path.exists(modal_toml):
3326
3326
  os.remove(modal_toml)
3327
- print(f"โœ… Deleted Modal token file at {modal_toml}")
3327
+ print(f"โœ… Deleted token file at {modal_toml}")
3328
3328
 
3329
- print("โœ… Modal token cleanup completed successfully")
3329
+ print("โœ… Token cleanup completed successfully")
3330
3330
  except Exception as e:
3331
- print(f"โŒ Error during Modal token cleanup: {e}")
3331
+ print(f"โŒ Error during token cleanup: {e}")
3332
3332
 
3333
3333
  def show_usage_examples():
3334
3334
  """Display usage examples for the script."""
@@ -3372,7 +3372,6 @@ if __name__ == "__main__":
3372
3372
  parser.add_argument('--timeout', type=int, default=60, help='Container timeout in minutes (default: 60)')
3373
3373
  parser.add_argument('--ssh-password', type=str, help='SSH password (random if not provided)')
3374
3374
  parser.add_argument('--use-api', action='store_true', help='Fetch setup commands from API')
3375
- parser.add_argument('--interactive', action='store_true', help='Run in interactive mode with prompts')
3376
3375
  parser.add_argument('--show-examples', action='store_true', help='Show usage examples')
3377
3376
 
3378
3377
  args = parser.parse_args()
@@ -3381,101 +3380,124 @@ if __name__ == "__main__":
3381
3380
  if len(sys.argv) == 1 or args.show_examples:
3382
3381
  show_usage_examples()
3383
3382
  sys.exit(0)
3384
-
3385
- # Get setup commands from file if specified
3386
- setup_commands = args.setup_commands or []
3387
-
3388
- # If --use-api flag is set and repo_url is provided, fetch setup commands from API
3389
-
3390
- # If --use-api flag is set and repo_url is provided, fetch setup commands from API
3391
- if args.use_api and args.repo_url:
3392
- print("๐Ÿ”„ Using API to fetch setup commands")
3393
- api_commands = fetch_setup_commands_from_api(args.repo_url)
3394
- if api_commands:
3395
- setup_commands = api_commands
3396
- print(f"๐Ÿ“‹ Using {len(setup_commands)} commands from API")
3397
- else:
3398
- print("โš ๏ธ Failed to get commands from API, no fallback commands will be used")
3399
- # Do not fall back to basic setup commands
3400
- setup_commands = []
3401
3383
 
3402
- # Parse setup commands from JSON if provided
3403
- if args.setup_commands_json:
3404
- try:
3405
- json_commands = json.loads(args.setup_commands_json)
3406
- if isinstance(json_commands, list):
3407
- setup_commands = json_commands
3408
- print(f"๐Ÿ“‹ Parsed {len(setup_commands)} commands from JSON:")
3409
- for i, cmd in enumerate(setup_commands, 1):
3410
- print(f" {i}. {cmd}")
3384
+ try:
3385
+ # Get setup commands from file if specified
3386
+ setup_commands = args.setup_commands or []
3387
+
3388
+ # If --use-api flag is set and repo_url is provided, fetch setup commands from API
3389
+
3390
+ # If --use-api flag is set and repo_url is provided, fetch setup commands from API
3391
+ if args.use_api and args.repo_url:
3392
+ print("๐Ÿ”„ Using API to fetch setup commands")
3393
+ api_commands = fetch_setup_commands_from_api(args.repo_url)
3394
+ if api_commands:
3395
+ setup_commands = api_commands
3396
+ print(f"๐Ÿ“‹ Using {len(setup_commands)} commands from API")
3411
3397
  else:
3412
- print(f"โš ๏ธ Invalid JSON format for setup commands: not a list")
3413
- except json.JSONDecodeError as e:
3414
- print(f"โš ๏ธ Error parsing JSON setup commands: {e}")
3415
- print(f"Received JSON string: {args.setup_commands_json}")
3416
-
3417
- # Print received setup commands for debugging
3418
- if setup_commands:
3419
- print(f"๐Ÿ“‹ Using {len(setup_commands)} setup commands:")
3420
- for i, cmd in enumerate(setup_commands, 1):
3421
- print(f" {i}. {cmd}")
3422
-
3423
- # Load commands from file if specified
3424
- if args.commands_file and os.path.exists(args.commands_file):
3425
- try:
3426
- with open(args.commands_file, 'r') as f:
3427
- # Check if the file contains JSON or line-by-line commands
3428
- content = f.read().strip()
3398
+ print("โš ๏ธ Failed to get commands from API, no fallback commands will be used")
3399
+ # Do not fall back to basic setup commands
3400
+ setup_commands = []
3401
+
3402
+ # Parse setup commands from JSON if provided
3403
+ if args.setup_commands_json:
3404
+ try:
3405
+ json_commands = json.loads(args.setup_commands_json)
3406
+ if isinstance(json_commands, list):
3407
+ setup_commands = json_commands
3408
+ print(f"๐Ÿ“‹ Parsed {len(setup_commands)} commands from JSON:")
3409
+ for i, cmd in enumerate(setup_commands, 1):
3410
+ print(f" {i}. {cmd}")
3411
+ else:
3412
+ print(f"โš ๏ธ Invalid JSON format for setup commands: not a list")
3413
+ except json.JSONDecodeError as e:
3414
+ print(f"โš ๏ธ Error parsing JSON setup commands: {e}")
3415
+ print(f"Received JSON string: {args.setup_commands_json}")
3416
+
3417
+ # Print received setup commands for debugging
3418
+ if setup_commands:
3419
+ print(f"๐Ÿ“‹ Using {len(setup_commands)} setup commands:")
3420
+ for i, cmd in enumerate(setup_commands, 1):
3421
+ print(f" {i}. {cmd}")
3429
3422
 
3430
- if content.startswith('[') and content.endswith(']'):
3431
- # JSON format
3432
- try:
3433
- json_commands = json.loads(content)
3434
- if isinstance(json_commands, list):
3435
- setup_commands.extend(json_commands)
3436
- print(f"๐Ÿ“‹ Loaded {len(json_commands)} commands from JSON file {args.commands_file}")
3437
- else:
3438
- print(f"โš ๏ธ Invalid JSON format in commands file: not a list")
3439
- except json.JSONDecodeError as json_err:
3440
- print(f"โš ๏ธ Error parsing JSON commands file: {json_err}")
3441
- # Fall back to line-by-line parsing
3423
+ # Load commands from file if specified
3424
+ if args.commands_file and os.path.exists(args.commands_file):
3425
+ try:
3426
+ with open(args.commands_file, 'r') as f:
3427
+ # Check if the file contains JSON or line-by-line commands
3428
+ content = f.read().strip()
3429
+
3430
+ if content.startswith('[') and content.endswith(']'):
3431
+ # JSON format
3432
+ try:
3433
+ json_commands = json.loads(content)
3434
+ if isinstance(json_commands, list):
3435
+ setup_commands.extend(json_commands)
3436
+ print(f"๐Ÿ“‹ Loaded {len(json_commands)} commands from JSON file {args.commands_file}")
3437
+ else:
3438
+ print(f"โš ๏ธ Invalid JSON format in commands file: not a list")
3439
+ except json.JSONDecodeError as json_err:
3440
+ print(f"โš ๏ธ Error parsing JSON commands file: {json_err}")
3441
+ # Fall back to line-by-line parsing
3442
+ file_commands = [line.strip() for line in content.split('\n') if line.strip()]
3443
+ setup_commands.extend(file_commands)
3444
+ print(f"๐Ÿ“‹ Loaded {len(file_commands)} commands from file (line-by-line fallback)")
3445
+ else:
3446
+ # Line-by-line format
3442
3447
  file_commands = [line.strip() for line in content.split('\n') if line.strip()]
3443
3448
  setup_commands.extend(file_commands)
3444
- print(f"๐Ÿ“‹ Loaded {len(file_commands)} commands from file (line-by-line fallback)")
3445
- else:
3446
- # Line-by-line format
3447
- file_commands = [line.strip() for line in content.split('\n') if line.strip()]
3448
- setup_commands.extend(file_commands)
3449
- print(f"๐Ÿ“‹ Loaded {len(file_commands)} commands from file (line-by-line format)")
3450
-
3451
- except Exception as e:
3452
- print(f"โš ๏ธ Error reading commands file: {e}")
3453
-
3454
- try:
3455
- result = create_modal_ssh_container(
3456
- args.gpu,
3457
- args.repo_url,
3458
- args.repo_name,
3459
- setup_commands,
3460
- getattr(args, 'volume_name', None),
3461
- args.timeout,
3462
- args.ssh_password
3463
- )
3449
+ print(f"๐Ÿ“‹ Loaded {len(file_commands)} commands from file (line-by-line format)")
3450
+ except Exception as e:
3451
+ print(f"โš ๏ธ Error loading commands from file: {e}")
3464
3452
 
3465
- print("\nโณ Keeping the SSH container alive. Press Ctrl+C to exit (container will continue running)...")
3466
- try:
3467
- while True:
3468
- time.sleep(90)
3469
- print(".", end="", flush=True)
3470
- except KeyboardInterrupt:
3471
- print("\n๐Ÿ‘‹ Script exited. The SSH container will continue running.")
3472
- sys.exit(0)
3473
-
3453
+ # Load commands from setup script if specified
3454
+ if args.setup_script and os.path.exists(args.setup_script):
3455
+ try:
3456
+ with open(args.setup_script, 'r') as f:
3457
+ script_content = f.read().strip()
3458
+ # Convert script to individual commands
3459
+ script_commands = [line.strip() for line in script_content.split('\n')
3460
+ if line.strip() and not line.strip().startswith('#')]
3461
+ setup_commands.extend(script_commands)
3462
+ print(f"๐Ÿ“‹ Loaded {len(script_commands)} commands from script {args.setup_script}")
3463
+ except Exception as e:
3464
+ print(f"โš ๏ธ Error loading commands from script: {e}")
3465
+
3466
+ # Create the container with the specified options
3467
+ if args.ssh_password:
3468
+ print(f"๐Ÿ”‘ Using provided SSH password")
3469
+ ssh_password = args.ssh_password
3470
+ else:
3471
+ ssh_password = generate_random_password()
3472
+ print(f"๐Ÿ”‘ Generated random SSH password: {ssh_password}")
3473
+
3474
+ # Extract repository name from URL if not provided
3475
+ repo_name = args.repo_name
3476
+ if not repo_name and args.repo_url:
3477
+ # Try to extract repo name from URL
3478
+ url_parts = args.repo_url.rstrip('/').split('/')
3479
+ if url_parts:
3480
+ repo_name = url_parts[-1]
3481
+ if repo_name.endswith('.git'):
3482
+ repo_name = repo_name[:-4]
3483
+
3484
+ # Create the container
3485
+ create_modal_ssh_container(
3486
+ gpu_type=args.gpu,
3487
+ repo_url=args.repo_url,
3488
+ repo_name=repo_name,
3489
+ setup_commands=setup_commands,
3490
+ volume_name=args.volume_name,
3491
+ timeout_minutes=args.timeout,
3492
+ ssh_password=ssh_password
3493
+ )
3474
3494
  except KeyboardInterrupt:
3475
- # Handle Ctrl+C during container creation
3476
- print("\n๐Ÿ‘‹ Script interrupted during container creation.")
3477
- print("๐Ÿ“ You may need to check if a container was created with: modal container list")
3478
- sys.exit(0)
3495
+ print("\n\n๐Ÿ›‘ Execution interrupted")
3496
+ print("๐Ÿงน Cleaning up resources...")
3497
+ cleanup_modal_token()
3498
+ sys.exit(1)
3479
3499
  except Exception as e:
3480
- print(f"โŒ Error: {e}")
3500
+ print(f"\nโŒ Error: {e}")
3501
+ print("๐Ÿงน Cleaning up resources...")
3502
+ cleanup_modal_token()
3481
3503
  sys.exit(1)