llm_fragments_repomix.py

 1from typing import List
 2import llm
 3import os
 4import pathlib
 5import subprocess
 6import tempfile
 7import shutil
 8
 9
10@llm.hookimpl
11def register_fragment_loaders(register):
12    register("repomix", repomix_loader)
13
14
15def repomix_loader(argument: str) -> List[llm.Fragment]:
16    """
17    Load repository contents as fragments using Repomix
18    
19    Argument is a git repository URL (https:// or ssh://)
20    Examples:
21        repomix:https://git.sr.ht/~amolith/willow
22        repomix:ssh://git.sr.ht:~amolith/willow
23    """
24    if not argument.startswith(("https://", "ssh://", "git@")):
25        raise ValueError(
26            f"Repository URL must start with https://, ssh://, or git@ - got: {argument}"
27        )
28    
29    # Check if repomix is available
30    if not shutil.which("repomix"):
31        raise ValueError(
32            "repomix command not found. Please install repomix first: "
33            "https://github.com/yamadashy/repomix"
34        )
35    
36    # Create a temporary directory for the cloned repository
37    with tempfile.TemporaryDirectory() as temp_dir:
38        repo_path = pathlib.Path(temp_dir) / "repo"
39        
40        try:
41            # Clone the repository
42            subprocess.run(
43                ["git", "clone", "--depth=1", argument, str(repo_path)],
44                check=True,
45                capture_output=True,
46                text=True,
47            )
48            
49            # Run repomix on the cloned repository
50            result = subprocess.run(
51                ["repomix", "--stdout", str(repo_path)],
52                check=True,
53                capture_output=True,
54                text=True,
55            )
56            
57            # Create a single fragment with the repomix output
58            fragments = [
59                llm.Fragment(
60                    content=result.stdout,
61                    source=f"repomix:{argument}"
62                )
63            ]
64            
65            return fragments
66            
67        except subprocess.CalledProcessError as e:
68            # Handle Git or repomix errors
69            if "git" in str(e.cmd):
70                raise ValueError(
71                    f"Failed to clone repository {argument}: {e.stderr}"
72                )
73            elif "repomix" in str(e.cmd):
74                raise ValueError(
75                    f"Failed to run repomix on {argument}: {e.stderr}"
76                )
77            else:
78                raise ValueError(
79                    f"Command failed: {e.stderr}"
80                )
81        except Exception as e:
82            # Handle other errors
83            raise ValueError(
84                f"Error processing repository {argument}: {str(e)}"
85            )