gitarsenal-cli 1.1.1 โ†’ 1.1.3

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.
@@ -478,36 +478,73 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
478
478
 
479
479
  # Check if Modal is authenticated
480
480
  try:
481
- # Try to list apps to check if authentication is working
482
- import subprocess
483
- result = subprocess.run(["modal", "app", "list"], capture_output=True, text=True)
484
- if result.returncode != 0 and "not authenticated" in result.stderr:
485
- print("๐Ÿ”‘ Modal authentication required")
486
-
487
- # Try to use credentials manager first
481
+ # Try to import modal first to check if it's installed
482
+ import modal
483
+
484
+ # Try to access Modal token to check authentication
485
+ try:
486
+ # This will raise an exception if not authenticated
487
+ modal.config.get_current_workspace_name()
488
+ print("โœ… Modal authentication verified")
489
+ except modal.exception.AuthError:
490
+ print("\n" + "="*80)
491
+ print("๐Ÿ”‘ MODAL AUTHENTICATION REQUIRED")
492
+ print("="*80)
493
+ print("GitArsenal requires Modal authentication to create cloud environments.")
494
+
495
+ # Try to get token from credentials manager
496
+ modal_token = None
488
497
  if credentials_manager:
489
- modal_token = credentials_manager.get_modal_token()
490
- if modal_token:
491
- # Set the token in the environment
492
- os.environ["MODAL_TOKEN_ID"] = modal_token
493
- print("โœ… Modal token set from credentials manager")
494
-
495
- # Try to authenticate with the token
496
- try:
497
- token_result = subprocess.run(["modal", "token", "set", modal_token],
498
- capture_output=True, text=True)
499
- if token_result.returncode == 0:
500
- print("โœ… Successfully authenticated with Modal")
501
- else:
502
- print(f"โš ๏ธ Failed to authenticate with Modal: {token_result.stderr}")
503
- print("Please run 'modal token new' manually and try again")
498
+ try:
499
+ modal_token = credentials_manager.get_modal_token()
500
+ if modal_token:
501
+ # Set the token in the environment
502
+ os.environ["MODAL_TOKEN_ID"] = modal_token
503
+ print("โœ… Modal token set from credentials manager")
504
+
505
+ # Try to authenticate with the token
506
+ try:
507
+ import subprocess
508
+ token_result = subprocess.run(
509
+ ["modal", "token", "set", modal_token],
510
+ capture_output=True, text=True
511
+ )
512
+ if token_result.returncode == 0:
513
+ print("โœ… Successfully authenticated with Modal")
514
+ else:
515
+ print(f"โš ๏ธ Failed to authenticate with Modal: {token_result.stderr}")
516
+ print("\nPlease authenticate manually:")
517
+ print("1. Run 'modal token new' to get a new token")
518
+ print("2. Then restart this command")
519
+ return None
520
+ except Exception as e:
521
+ print(f"โš ๏ธ Error setting Modal token: {e}")
504
522
  return None
505
- except Exception as e:
506
- print(f"โš ๏ธ Error setting Modal token: {e}")
507
- return None
508
- else:
509
- print("โš ๏ธ Modal is not authenticated. Please run 'modal token new' first")
523
+ except Exception as e:
524
+ print(f"โš ๏ธ Error getting Modal token: {e}")
525
+
526
+ if not modal_token:
527
+ print("\nTo authenticate with Modal, you need to:")
528
+ print("1. Create a Modal account at https://modal.com if you don't have one")
529
+ print("2. Run the following command to get a token:")
530
+ print(" modal token new")
531
+ print("3. Then set up your credentials in GitArsenal:")
532
+ print(" ./gitarsenal.py credentials set modal_token")
533
+ print("\nAfter completing these steps, try your command again.")
534
+ print("="*80)
510
535
  return None
536
+ except ImportError:
537
+ print("\n" + "="*80)
538
+ print("โŒ MODAL PACKAGE NOT INSTALLED")
539
+ print("="*80)
540
+ print("GitArsenal requires the Modal package to be installed.")
541
+ print("\nTo install Modal, run:")
542
+ print(" pip install modal")
543
+ print("\nAfter installation, authenticate with Modal:")
544
+ print("1. Run 'modal token new'")
545
+ print("2. Then run './gitarsenal.py credentials set modal_token'")
546
+ print("="*80)
547
+ return None
511
548
  except Exception as e:
512
549
  print(f"โš ๏ธ Error checking Modal authentication: {e}")
513
550
  print("Continuing anyway, but Modal operations may fail")
@@ -2393,53 +2430,177 @@ def fetch_setup_commands_from_api(repo_url):
2393
2430
 
2394
2431
  # Make the API request
2395
2432
  print(f"๐ŸŒ Making POST request to: {api_url}")
2396
- response = requests.post(api_url, json=payload, timeout=60)
2397
-
2398
- print(f"๐Ÿ“ฅ API Response status code: {response.status_code}")
2399
-
2400
- if response.status_code == 200:
2401
- try:
2402
- data = response.json()
2403
- print(f"๐Ÿ“„ API Response data received")
2404
-
2405
- # Extract setup commands from the response
2406
- if "setupInstructions" in data and "commands" in data["setupInstructions"]:
2407
- commands = data["setupInstructions"]["commands"]
2408
- print(f"โœ… Successfully fetched {len(commands)} setup commands from API")
2409
-
2410
- # Print the commands for reference
2411
- for i, cmd in enumerate(commands, 1):
2412
- print(f" {i}. {cmd}")
2433
+ try:
2434
+ response = requests.post(api_url, json=payload, timeout=60)
2435
+
2436
+ print(f"๐Ÿ“ฅ API Response status code: {response.status_code}")
2437
+
2438
+ if response.status_code == 200:
2439
+ try:
2440
+ data = response.json()
2441
+ print(f"๐Ÿ“„ API Response data received")
2413
2442
 
2414
- return commands
2415
- else:
2416
- print("โš ๏ธ API response did not contain setupInstructions.commands field")
2417
- print("๐Ÿ“‹ Available fields in response:")
2418
- for key in data.keys():
2419
- print(f" - {key}")
2420
- return []
2421
- except json.JSONDecodeError as e:
2422
- print(f"โŒ Failed to parse API response as JSON: {e}")
2423
- print(f"Raw response: {response.text[:500]}...")
2424
- return []
2425
- else:
2426
- print(f"โŒ API request failed with status code: {response.status_code}")
2427
- print(f"Error response: {response.text[:500]}...")
2428
- return []
2429
- except requests.exceptions.ConnectionError:
2430
- print(f"โŒ Connection error: Could not connect to {api_url}")
2431
- print("โš ๏ธ Make sure the API server is running at localhost:3000")
2432
- return []
2443
+ # Extract setup commands from the response
2444
+ if "setupInstructions" in data and "commands" in data["setupInstructions"]:
2445
+ commands = data["setupInstructions"]["commands"]
2446
+ print(f"โœ… Successfully fetched {len(commands)} setup commands from API")
2447
+
2448
+ # Print the commands for reference
2449
+ for i, cmd in enumerate(commands, 1):
2450
+ print(f" {i}. {cmd}")
2451
+
2452
+ return commands
2453
+ else:
2454
+ print("โš ๏ธ API response did not contain setupInstructions.commands field")
2455
+ print("๐Ÿ“‹ Available fields in response:")
2456
+ for key in data.keys():
2457
+ print(f" - {key}")
2458
+ # Return fallback commands
2459
+ return generate_fallback_commands(gitingest_data)
2460
+ except json.JSONDecodeError as e:
2461
+ print(f"โŒ Failed to parse API response as JSON: {e}")
2462
+ print(f"Raw response: {response.text[:500]}...")
2463
+ # Return fallback commands
2464
+ return generate_fallback_commands(gitingest_data)
2465
+ elif response.status_code == 504:
2466
+ print(f"โŒ API request timed out (504 Gateway Timeout)")
2467
+ print("โš ๏ธ The server took too long to respond. Using fallback commands instead.")
2468
+ # Return fallback commands
2469
+ return generate_fallback_commands(gitingest_data)
2470
+ else:
2471
+ print(f"โŒ API request failed with status code: {response.status_code}")
2472
+ print(f"Error response: {response.text[:500]}...")
2473
+ # Return fallback commands
2474
+ return generate_fallback_commands(gitingest_data)
2475
+ except requests.exceptions.Timeout:
2476
+ print("โŒ API request timed out after 60 seconds")
2477
+ print("โš ๏ธ Using fallback commands instead")
2478
+ # Return fallback commands
2479
+ return generate_fallback_commands(gitingest_data)
2480
+ except requests.exceptions.ConnectionError:
2481
+ print(f"โŒ Connection error: Could not connect to {api_url}")
2482
+ print("โš ๏ธ Using fallback commands instead")
2483
+ # Return fallback commands
2484
+ return generate_fallback_commands(gitingest_data)
2433
2485
  except Exception as e:
2434
2486
  print(f"โŒ Error fetching setup commands from API: {e}")
2435
2487
  import traceback
2436
2488
  traceback.print_exc()
2437
- return []
2489
+ # Return fallback commands
2490
+ return generate_fallback_commands(None)
2438
2491
  finally:
2439
2492
  # Clean up the temporary directory
2440
2493
  print(f"๐Ÿงน Cleaning up temporary directory...")
2441
2494
  shutil.rmtree(temp_dir, ignore_errors=True)
2442
2495
 
2496
+ def generate_fallback_commands(gitingest_data):
2497
+ """Generate fallback setup commands based on repository analysis"""
2498
+ print("\n" + "="*80)
2499
+ print("๐Ÿ“‹ GENERATING FALLBACK SETUP COMMANDS")
2500
+ print("="*80)
2501
+ print("Using basic repository analysis to generate setup commands")
2502
+
2503
+ # Default commands that work for most repositories
2504
+ default_commands = [
2505
+ "apt-get update -y",
2506
+ "apt-get install -y git curl wget",
2507
+ "pip install --upgrade pip setuptools wheel"
2508
+ ]
2509
+
2510
+ # If we don't have any analysis data, return default commands
2511
+ if not gitingest_data:
2512
+ print("โš ๏ธ No repository analysis data available. Using default commands.")
2513
+ return default_commands
2514
+
2515
+ # Extract language and technologies information
2516
+ detected_language = gitingest_data.get("system_info", {}).get("detected_language", "Unknown")
2517
+ detected_technologies = gitingest_data.get("system_info", {}).get("detected_technologies", [])
2518
+ primary_package_manager = gitingest_data.get("system_info", {}).get("primary_package_manager", "Unknown")
2519
+
2520
+ # Add language-specific commands
2521
+ language_commands = []
2522
+
2523
+ print(f"๐Ÿ“‹ Detected primary language: {detected_language}")
2524
+ print(f"๐Ÿ“‹ Detected technologies: {', '.join(detected_technologies) if detected_technologies else 'None'}")
2525
+ print(f"๐Ÿ“‹ Detected package manager: {primary_package_manager}")
2526
+
2527
+ # Python-specific commands
2528
+ if detected_language == "Python" or primary_package_manager == "pip":
2529
+ print("๐Ÿ“ฆ Adding Python-specific setup commands")
2530
+
2531
+ # Check for requirements.txt
2532
+ requirements_check = [
2533
+ "if [ -f requirements.txt ]; then",
2534
+ " echo 'Installing from requirements.txt'",
2535
+ " pip install -r requirements.txt",
2536
+ "elif [ -f setup.py ]; then",
2537
+ " echo 'Installing from setup.py'",
2538
+ " pip install -e .",
2539
+ "fi"
2540
+ ]
2541
+ language_commands.extend(requirements_check)
2542
+
2543
+ # Add common Python packages
2544
+ language_commands.append("pip install pytest numpy pandas matplotlib")
2545
+
2546
+ # JavaScript/Node.js specific commands
2547
+ elif detected_language in ["JavaScript", "TypeScript"] or primary_package_manager in ["npm", "yarn", "pnpm"]:
2548
+ print("๐Ÿ“ฆ Adding JavaScript/Node.js-specific setup commands")
2549
+
2550
+ # Install Node.js if not available
2551
+ language_commands.append("apt-get install -y nodejs npm")
2552
+
2553
+ # Check for package.json
2554
+ package_json_check = [
2555
+ "if [ -f package.json ]; then",
2556
+ " echo 'Installing from package.json'",
2557
+ " npm install",
2558
+ "fi"
2559
+ ]
2560
+ language_commands.extend(package_json_check)
2561
+
2562
+ # Java specific commands
2563
+ elif detected_language == "Java" or primary_package_manager in ["maven", "gradle"]:
2564
+ print("๐Ÿ“ฆ Adding Java-specific setup commands")
2565
+
2566
+ language_commands.append("apt-get install -y openjdk-11-jdk maven gradle")
2567
+
2568
+ # Check for Maven or Gradle
2569
+ build_check = [
2570
+ "if [ -f pom.xml ]; then",
2571
+ " echo 'Building with Maven'",
2572
+ " mvn clean install -DskipTests",
2573
+ "elif [ -f build.gradle ]; then",
2574
+ " echo 'Building with Gradle'",
2575
+ " gradle build --no-daemon",
2576
+ "fi"
2577
+ ]
2578
+ language_commands.extend(build_check)
2579
+
2580
+ # Go specific commands
2581
+ elif detected_language == "Go" or primary_package_manager == "go":
2582
+ print("๐Ÿ“ฆ Adding Go-specific setup commands")
2583
+
2584
+ language_commands.append("apt-get install -y golang-go")
2585
+ language_commands.append("go mod tidy")
2586
+
2587
+ # Rust specific commands
2588
+ elif detected_language == "Rust" or primary_package_manager == "cargo":
2589
+ print("๐Ÿ“ฆ Adding Rust-specific setup commands")
2590
+
2591
+ language_commands.append("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y")
2592
+ language_commands.append("source $HOME/.cargo/env")
2593
+ language_commands.append("cargo build")
2594
+
2595
+ # Combine all commands
2596
+ all_commands = default_commands + language_commands
2597
+
2598
+ print("\n๐Ÿ“‹ Generated fallback setup commands:")
2599
+ for i, cmd in enumerate(all_commands, 1):
2600
+ print(f" {i}. {cmd}")
2601
+
2602
+ return all_commands
2603
+
2443
2604
  def generate_basic_repo_analysis_from_url(repo_url):
2444
2605
  """Generate basic repository analysis data from a repository URL."""
2445
2606
  import tempfile