gitarsenal-cli 1.3.7 → 1.3.8

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.7",
3
+ "version": "1.3.8",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -2559,215 +2559,111 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
2559
2559
  return None
2560
2560
 
2561
2561
  def fetch_setup_commands_from_api(repo_url):
2562
- """Fetch setup commands from the GitIngest API using real repository analysis."""
2562
+ """Generate setup commands locally using GitIngest analysis without API calls."""
2563
2563
  import tempfile
2564
2564
  import subprocess
2565
2565
  import os
2566
2566
  import shutil
2567
2567
  import json
2568
2568
 
2569
- api_url = "https://git-arsenal.vercel.app/api/analyze-with-gitingest"
2569
+ print(f"šŸ” Analyzing repository: {repo_url}")
2570
2570
 
2571
- print(f"šŸ” Fetching setup commands from API for repository: {repo_url}")
2572
-
2573
- # Check if gitingest command line tool is available - try multiple possible command names
2574
- has_gitingest_cli = False
2575
- gitingest_cmd_name = None
2576
-
2577
- # Try the standard command name first
2571
+ # Check if gitingest command line tool is available
2578
2572
  try:
2579
2573
  print(f"šŸ” Checking for GitIngest CLI tool...")
2580
2574
  result = subprocess.run(["gitingest", "--help"], check=True, capture_output=True, text=True)
2581
- has_gitingest_cli = True
2582
- gitingest_cmd_name = "gitingest"
2583
2575
  print(f"āœ… GitIngest CLI tool found")
2584
2576
  except (subprocess.SubprocessError, FileNotFoundError) as e:
2585
- print(f" - GitIngest command not found: {str(e)}")
2577
+ print(f"āŒ GitIngest CLI tool not found: {str(e)}")
2578
+ return generate_fallback_commands(None)
2586
2579
 
2587
2580
  # Create a temporary directory for output
2588
2581
  temp_dir = tempfile.mkdtemp(prefix="repo_analysis_")
2589
2582
  output_file = os.path.join(temp_dir, "digest.json")
2590
2583
 
2591
2584
  try:
2592
- if has_gitingest_cli:
2593
- # Use gitingest CLI tool to analyze the repository directly from URL
2594
- print(f"šŸ”Ž Running GitIngest analysis on {repo_url}...")
2595
-
2596
- # Based on the help output, the correct format is:
2597
- # gitingest [OPTIONS] [SOURCE]
2598
- # With options:
2599
- # -o, --output TEXT Output file path
2600
- # --format TEXT Output format (json)
2601
-
2602
- # Run gitingest command with proper parameters
2603
- gitingest_run_cmd = [
2604
- gitingest_cmd_name,
2605
- repo_url,
2606
- "-o", output_file, # Use -o for output file
2607
- ]
2608
-
2609
- print(f"šŸ”„ Executing: {' '.join(gitingest_run_cmd)}")
2610
-
2611
- result = subprocess.run(gitingest_run_cmd, capture_output=True, text=True)
2612
-
2613
- if result.returncode != 0:
2614
- print(f"āš ļø GitIngest CLI failed with exit code {result.returncode}")
2615
- print(f"āš ļø Error output: {result.stderr}")
2616
- print("Falling back to basic analysis")
2617
- gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
2618
- else:
2619
- print(f"āœ… GitIngest analysis completed successfully")
2620
-
2621
- # Read the output file - GitIngest outputs structured text, not JSON
2622
- try:
2623
- with open(output_file, 'r', encoding='utf-8') as f:
2624
- content = f.read()
2625
-
2626
- # Process the text output into a structured format
2627
- print(f"šŸ“„ Processing GitIngest text output")
2628
-
2629
- # Extract key information from the text output
2630
- import re
2631
-
2632
- # Try to identify language
2633
- language_match = re.search(r"(?i)language[s]?:?\s*(\w+)", content)
2634
- detected_language = language_match.group(1) if language_match else "Unknown"
2635
-
2636
- # Try to identify technologies
2637
- tech_matches = re.findall(r"(?i)(python|javascript|typescript|react|node|vue|angular|django|flask|express|pytorch|tensorflow|rust|go|ruby|rails|php|laravel|c\+\+|java|kotlin|swift)", content)
2638
- detected_technologies = list(set(tech_matches)) if tech_matches else []
2639
-
2640
- # Create a structured representation
2641
- gitingest_data = {
2642
- "system_info": {
2643
- "detected_language": detected_language,
2644
- "detected_technologies": detected_technologies,
2645
- },
2646
- "repository_analysis": {
2647
- "summary": content[:1000], # First 1000 chars as summary
2648
- "content_preview": content[:5000] # First 5000 chars as preview
2649
- },
2650
- "raw_text": content[:10000], # Include a portion of the raw text
2651
- "success": True
2652
- }
2653
-
2654
- print(f"šŸ“„ Processed GitIngest output: Detected language: {detected_language}, Technologies: {', '.join(detected_technologies) if detected_technologies else 'None'}")
2655
-
2656
- except FileNotFoundError:
2657
- print(f"āš ļø Output file not found at {output_file}")
2658
- gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
2659
- except Exception as e:
2660
- print(f"āš ļø Error reading GitIngest output: {e}")
2661
- gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
2662
- else:
2663
- # Fall back to basic analysis if gitingest CLI is not available
2664
- gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
2665
-
2666
- # Prepare the request payload with GitIngest data
2667
- payload = {
2668
- "repoUrl": repo_url,
2669
- "gitingestData": gitingest_data,
2670
- "userRequest": "Setup and run the repository"
2671
- }
2585
+ # Use gitingest CLI tool to analyze the repository directly from URL
2586
+ print(f"šŸ”Ž Running GitIngest analysis on {repo_url}...")
2587
+
2588
+ # Run gitingest command with proper parameters
2589
+ gitingest_run_cmd = [
2590
+ "gitingest",
2591
+ repo_url,
2592
+ "-o", output_file,
2593
+ ]
2594
+
2595
+ print(f"šŸ”„ Executing: {' '.join(gitingest_run_cmd)}")
2672
2596
 
2673
- print(f"šŸ“¤ API Request payload prepared (GitIngest data size: {len(json.dumps(gitingest_data))} bytes)")
2597
+ result = subprocess.run(gitingest_run_cmd, capture_output=True, text=True)
2674
2598
 
2675
- # Make the API request with a shorter timeout to avoid long waits
2676
- print(f"🌐 Making POST request to: {api_url}")
2599
+ if result.returncode != 0:
2600
+ print(f"āš ļø GitIngest CLI failed with exit code {result.returncode}")
2601
+ print(f"āš ļø Error output: {result.stderr}")
2602
+ print("Falling back to basic analysis")
2603
+ return generate_fallback_commands(None)
2604
+
2605
+ print(f"āœ… GitIngest analysis completed successfully")
2606
+
2607
+ # Read the output file - GitIngest outputs structured text, not JSON
2677
2608
  try:
2678
- response = requests.post(api_url, json=payload, timeout=30) # Reduced timeout to 30 seconds
2609
+ with open(output_file, 'r', encoding='utf-8') as f:
2610
+ content = f.read()
2611
+
2612
+ # Process the text output into a structured format
2613
+ print(f"šŸ“„ Processing GitIngest text output")
2614
+
2615
+ # Extract key information from the text output
2616
+ import re
2617
+
2618
+ # Try to identify language
2619
+ language_match = re.search(r"(?i)language[s]?:?\s*(\w+)", content)
2620
+ detected_language = language_match.group(1) if language_match else "Unknown"
2621
+
2622
+ # Try to identify technologies
2623
+ tech_patterns = {
2624
+ "python": r"(?i)(python|\.py\b|pip\b|requirements\.txt|setup\.py)",
2625
+ "javascript": r"(?i)(javascript|\.js\b|node|npm|yarn|package\.json)",
2626
+ "typescript": r"(?i)(typescript|\.ts\b|tsc\b|tsconfig\.json)",
2627
+ "go": r"(?i)(\bgo\b|golang|\.go\b|go\.mod|go\.sum)",
2628
+ "rust": r"(?i)(rust|\.rs\b|cargo|Cargo\.toml)",
2629
+ "java": r"(?i)(java\b|\.java\b|maven|gradle|pom\.xml)",
2630
+ "c++": r"(?i)(c\+\+|\.cpp\b|\.hpp\b|cmake\b|CMakeLists\.txt)",
2631
+ "pytorch": r"(?i)(pytorch|torch\b|nn\.Module)",
2632
+ "tensorflow": r"(?i)(tensorflow|tf\.|keras\b)",
2633
+ }
2679
2634
 
2680
- print(f"šŸ“„ API Response status code: {response.status_code}")
2635
+ detected_technologies = []
2636
+ for tech, pattern in tech_patterns.items():
2637
+ if re.search(pattern, content):
2638
+ detected_technologies.append(tech)
2681
2639
 
2682
- if response.status_code == 200:
2683
- try:
2684
- data = response.json()
2685
- print(f"šŸ“„ API Response data received")
2686
-
2687
- # Extract setup commands from the response
2688
- if "setupInstructions" in data and "commands" in data["setupInstructions"]:
2689
- commands = data["setupInstructions"]["commands"]
2690
- print(f"āœ… Successfully fetched {len(commands)} setup commands from API")
2691
-
2692
- # Print the original commands for reference
2693
- print("šŸ“‹ Original commands from API:")
2694
- for i, cmd in enumerate(commands, 1):
2695
- print(f" {i}. {cmd}")
2696
-
2697
- # Fix the commands by removing placeholders and comments
2698
- fixed_commands = fix_setup_commands(commands)
2699
-
2700
- # If we have a temp_dir with the cloned repo, try to find the entry point
2701
- # and replace any placeholder entry points
2702
- for i, cmd in enumerate(fixed_commands):
2703
- if "python main.py" in cmd or "python3 main.py" in cmd:
2704
- try:
2705
- entry_point = find_entry_point(temp_dir)
2706
- if entry_point and entry_point != "main.py":
2707
- fixed_commands[i] = cmd.replace("main.py", entry_point)
2708
- print(f"šŸ”„ Replaced main.py with detected entry point: {entry_point}")
2709
- except Exception as e:
2710
- print(f"āš ļø Error finding entry point: {e}")
2711
-
2712
- # Print the fixed commands
2713
- print("\nšŸ“‹ Fixed commands:")
2714
- for i, cmd in enumerate(fixed_commands, 1):
2715
- print(f" {i}. {cmd}")
2716
-
2717
- return fixed_commands
2718
- else:
2719
- print("āš ļø API response did not contain setupInstructions.commands field")
2720
- print("šŸ“‹ Available fields in response:")
2721
- for key in data.keys():
2722
- print(f" - {key}")
2723
-
2724
- # Generate fallback commands based on the gitingest data
2725
- print("\n" + "="*80)
2726
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2727
- print("="*80)
2728
- fallback_commands = generate_fallback_commands(gitingest_data)
2729
- return fallback_commands
2730
- except Exception as e:
2731
- print(f"āš ļø Error parsing API response: {e}")
2732
- elif response.status_code == 504:
2733
- print(f"āŒ API request timed out (504 Gateway Timeout)")
2734
- print(f"āš ļø The server took too long to respond. Using fallback commands instead.")
2735
-
2736
- # Generate fallback commands based on the gitingest data
2737
- print("\n" + "="*80)
2738
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2739
- print("="*80)
2740
- fallback_commands = generate_fallback_commands(gitingest_data)
2741
- return fallback_commands
2742
- else:
2743
- print(f"āŒ API request failed with status code {response.status_code}")
2744
- print(f"Response: {response.text[:500]}")
2745
-
2746
- # Generate fallback commands based on the gitingest data
2747
- print("\n" + "="*80)
2748
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2749
- print("="*80)
2750
- fallback_commands = generate_fallback_commands(gitingest_data)
2751
- return fallback_commands
2752
- except requests.exceptions.Timeout:
2753
- print(f"āŒ API request timed out after 30 seconds")
2754
- print(f"āš ļø The server took too long to respond. Using fallback commands instead.")
2640
+ # Create a structured representation
2641
+ gitingest_data = {
2642
+ "system_info": {
2643
+ "detected_language": detected_language,
2644
+ "detected_technologies": detected_technologies,
2645
+ },
2646
+ "repository_analysis": {
2647
+ "summary": content[:1000], # First 1000 chars as summary
2648
+ "content_preview": content[:5000] # First 5000 chars as preview
2649
+ },
2650
+ "raw_text": content[:10000], # Include a portion of the raw text
2651
+ "success": True
2652
+ }
2755
2653
 
2756
- # Generate fallback commands based on the gitingest data
2757
- print("\n" + "="*80)
2758
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2759
- print("="*80)
2760
- fallback_commands = generate_fallback_commands(gitingest_data)
2761
- return fallback_commands
2762
- except Exception as e:
2763
- print(f"āŒ Error making API request: {e}")
2654
+ print(f"šŸ“„ Processed GitIngest output: Detected language: {detected_language}, Technologies: {', '.join(detected_technologies) if detected_technologies else 'None'}")
2764
2655
 
2765
- # Generate fallback commands based on the gitingest data
2766
- print("\n" + "="*80)
2767
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2768
- print("="*80)
2769
- fallback_commands = generate_fallback_commands(gitingest_data)
2770
- return fallback_commands
2656
+ # Generate commands locally based on the analysis
2657
+ print(f"šŸ”§ Generating setup commands locally based on repository analysis")
2658
+ setup_commands = generate_fallback_commands(gitingest_data)
2659
+ return setup_commands
2660
+
2661
+ except FileNotFoundError:
2662
+ print(f"āš ļø Output file not found at {output_file}")
2663
+ return generate_fallback_commands(None)
2664
+ except Exception as e:
2665
+ print(f"āš ļø Error processing GitIngest output: {e}")
2666
+ return generate_fallback_commands(None)
2771
2667
  finally:
2772
2668
  # Clean up temporary directory
2773
2669
  print(f"🧹 Cleaning up temporary directory...")
@@ -2785,9 +2681,6 @@ def fetch_setup_commands_from_api(repo_url):
2785
2681
 
2786
2682
  def generate_fallback_commands(gitingest_data):
2787
2683
  """Generate fallback setup commands based on repository analysis"""
2788
- print("\n" + "="*80)
2789
- print("šŸ“‹ GENERATING FALLBACK SETUP COMMANDS")
2790
- print("="*80)
2791
2684
  print("Using basic repository analysis to generate setup commands")
2792
2685
 
2793
2686
  # Default commands that work for most repositories
@@ -2807,6 +2700,28 @@ def generate_fallback_commands(gitingest_data):
2807
2700
  detected_technologies = gitingest_data.get("system_info", {}).get("detected_technologies", [])
2808
2701
  primary_package_manager = gitingest_data.get("system_info", {}).get("primary_package_manager", "Unknown")
2809
2702
 
2703
+ # Extract more information from raw text if available
2704
+ if "raw_text" in gitingest_data and gitingest_data["raw_text"]:
2705
+ raw_text = gitingest_data["raw_text"]
2706
+
2707
+ # Look for additional technologies in raw text
2708
+ import re
2709
+ tech_patterns = {
2710
+ "python": r"(?i)(python|\.py\b|pip\b|requirements\.txt|setup\.py)",
2711
+ "javascript": r"(?i)(javascript|\.js\b|node|npm|yarn|package\.json)",
2712
+ "typescript": r"(?i)(typescript|\.ts\b|tsc\b|tsconfig\.json)",
2713
+ "go": r"(?i)(\bgo\b|golang|\.go\b|go\.mod|go\.sum)",
2714
+ "rust": r"(?i)(rust|\.rs\b|cargo|Cargo\.toml)",
2715
+ "java": r"(?i)(java\b|\.java\b|maven|gradle|pom\.xml)",
2716
+ "c++": r"(?i)(c\+\+|\.cpp\b|\.hpp\b|cmake\b|CMakeLists\.txt)",
2717
+ "pytorch": r"(?i)(pytorch|torch\b|nn\.Module)",
2718
+ "tensorflow": r"(?i)(tensorflow|tf\.|keras\b)",
2719
+ }
2720
+
2721
+ for tech, pattern in tech_patterns.items():
2722
+ if re.search(pattern, raw_text) and tech.lower() not in [t.lower() for t in detected_technologies]:
2723
+ detected_technologies.append(tech)
2724
+
2810
2725
  # Add language-specific commands
2811
2726
  language_commands = []
2812
2727
 
@@ -2814,12 +2729,21 @@ def generate_fallback_commands(gitingest_data):
2814
2729
  print(f"šŸ“‹ Detected technologies: {', '.join(detected_technologies) if detected_technologies else 'None'}")
2815
2730
  print(f"šŸ“‹ Detected package manager: {primary_package_manager}")
2816
2731
 
2732
+ # Check for specific technologies and add appropriate commands
2733
+ has_python = any(tech.lower() == "python" for tech in detected_technologies) or detected_language.lower() == "python"
2734
+ has_js = any(tech.lower() in ["javascript", "node", "nodejs"] for tech in detected_technologies)
2735
+ has_ts = any(tech.lower() == "typescript" for tech in detected_technologies)
2736
+ has_go = any(tech.lower() in ["go", "golang"] for tech in detected_technologies)
2737
+ has_pytorch = any(tech.lower() in ["pytorch", "torch"] for tech in detected_technologies)
2738
+ has_tensorflow = any(tech.lower() == "tensorflow" for tech in detected_technologies)
2739
+
2817
2740
  # Python-specific commands
2818
- if detected_language == "Python" or primary_package_manager == "pip":
2741
+ if has_python:
2819
2742
  print("šŸ“¦ Adding Python-specific setup commands")
2743
+ language_commands.append("apt-get install -y python3 python3-pip python3-dev")
2820
2744
 
2821
2745
  # Check for requirements.txt
2822
- requirements_check = [
2746
+ language_commands.extend([
2823
2747
  "if [ -f requirements.txt ]; then",
2824
2748
  " echo 'Installing from requirements.txt'",
2825
2749
  " pip install -r requirements.txt",
@@ -2827,72 +2751,56 @@ def generate_fallback_commands(gitingest_data):
2827
2751
  " echo 'Installing from setup.py'",
2828
2752
  " pip install -e .",
2829
2753
  "fi"
2830
- ]
2831
- language_commands.extend(requirements_check)
2832
-
2833
- # Add common Python packages
2834
- language_commands.append("pip install pytest numpy pandas matplotlib")
2754
+ ])
2835
2755
 
2836
2756
  # JavaScript/Node.js specific commands
2837
- elif detected_language in ["JavaScript", "TypeScript"] or primary_package_manager in ["npm", "yarn", "pnpm"]:
2757
+ if has_js or has_ts:
2838
2758
  print("šŸ“¦ Adding JavaScript/Node.js-specific setup commands")
2759
+ language_commands.append("curl -fsSL https://deb.nodesource.com/setup_18.x | bash -")
2760
+ language_commands.append("apt-get install -y nodejs")
2839
2761
 
2840
- # Install Node.js if not available
2841
- language_commands.append("apt-get install -y nodejs npm")
2762
+ # Install TypeScript if detected
2763
+ if has_ts:
2764
+ language_commands.append("npm install -g typescript ts-node")
2842
2765
 
2843
2766
  # Check for package.json
2844
- package_json_check = [
2767
+ language_commands.extend([
2845
2768
  "if [ -f package.json ]; then",
2846
- " echo 'Installing from package.json'",
2769
+ " echo 'Installing npm dependencies'",
2847
2770
  " npm install",
2848
2771
  "fi"
2849
- ]
2850
- language_commands.extend(package_json_check)
2851
-
2852
- # Java specific commands
2853
- elif detected_language == "Java" or primary_package_manager in ["maven", "gradle"]:
2854
- print("šŸ“¦ Adding Java-specific setup commands")
2855
-
2856
- language_commands.append("apt-get install -y openjdk-11-jdk maven gradle")
2857
-
2858
- # Check for Maven or Gradle
2859
- build_check = [
2860
- "if [ -f pom.xml ]; then",
2861
- " echo 'Building with Maven'",
2862
- " mvn clean install -DskipTests",
2863
- "elif [ -f build.gradle ]; then",
2864
- " echo 'Building with Gradle'",
2865
- " gradle build --no-daemon",
2866
- "fi"
2867
- ]
2868
- language_commands.extend(build_check)
2772
+ ])
2869
2773
 
2870
- # Go specific commands
2871
- elif detected_language == "Go" or primary_package_manager == "go":
2774
+ # Go-specific commands
2775
+ if has_go:
2872
2776
  print("šŸ“¦ Adding Go-specific setup commands")
2873
-
2874
- language_commands.append("apt-get install -y golang-go")
2875
- language_commands.append("go mod tidy")
2777
+ language_commands.append("apt-get install -y golang")
2778
+ language_commands.extend([
2779
+ "if [ -f go.mod ]; then",
2780
+ " echo 'Installing Go dependencies'",
2781
+ " go mod download",
2782
+ "fi"
2783
+ ])
2876
2784
 
2877
- # Rust specific commands
2878
- elif detected_language == "Rust" or primary_package_manager == "cargo":
2879
- print("šŸ“¦ Adding Rust-specific setup commands")
2880
-
2881
- language_commands.append("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y")
2882
- language_commands.append("source $HOME/.cargo/env")
2883
- language_commands.append("cargo build")
2785
+ # PyTorch-specific commands
2786
+ if has_pytorch:
2787
+ print("šŸ“¦ Adding PyTorch-specific setup commands")
2788
+ language_commands.append("pip install torch torchvision torchaudio")
2884
2789
 
2885
- # Combine all commands
2886
- all_commands = default_commands + language_commands
2790
+ # TensorFlow-specific commands
2791
+ if has_tensorflow:
2792
+ print("šŸ“¦ Adding TensorFlow-specific setup commands")
2793
+ language_commands.append("pip install tensorflow tensorflow-gpu")
2887
2794
 
2888
- # Fix the commands
2889
- fixed_commands = fix_setup_commands(all_commands)
2795
+ # Combine default commands with language-specific commands
2796
+ all_commands = default_commands + language_commands
2890
2797
 
2798
+ # Print the generated commands
2891
2799
  print("\nšŸ“‹ Generated fallback setup commands:")
2892
- for i, cmd in enumerate(fixed_commands, 1):
2800
+ for i, cmd in enumerate(all_commands, 1):
2893
2801
  print(f" {i}. {cmd}")
2894
2802
 
2895
- return fixed_commands
2803
+ return all_commands
2896
2804
 
2897
2805
  def generate_basic_repo_analysis_from_url(repo_url):
2898
2806
  """Generate basic repository analysis data from a repository URL."""