scider / scievo /tools /github_tool.py
harry-lu-0708's picture
clean HF Space commit (no binary history)
0913c52
import os
import shutil
from pathlib import Path
from .registry import register_tool, register_toolset_desc
register_toolset_desc(
"github", "Tools for interacting with GitHub repositories on the local system."
)
@register_tool(
"github",
{
"type": "function",
"function": {
"name": "clone_repo",
"description": "Clone a GitHub repository to a target local directory.",
"parameters": {
"type": "object",
"properties": {
"repo_url": {
"type": "string",
"description": "HTTP(S) URL of the GitHub repository to clone.",
},
"dest_dir": {
"type": "string",
"description": "Local directory path where the repository will be cloned.",
},
},
"required": ["repo_url", "dest_dir"],
},
},
},
)
def clone_repo(repo_url: str, dest_dir: str) -> str:
"""
Clone a GitHub repository into a given local directory.
Workflow:
1. Expand user and environment variables in dest_dir.
2. Ensure directory exists; create it if needed.
3. Run `git clone` using shutil and system git.
4. Return success or error message.
"""
try:
dest_path = Path(os.path.expandvars(dest_dir)).expanduser()
dest_path.mkdir(parents=True, exist_ok=True)
# Determine repository name from URL
repo_name = repo_url.rstrip("/").split("/")[-1].replace(".git", "")
destination = dest_path / repo_name
# Remove existing directory to avoid git conflict
if destination.exists():
shutil.rmtree(destination)
# Perform clone
result = os.system(f"git clone {repo_url} {destination}")
if result != 0:
return f"Error: Failed to clone repository from {repo_url}"
return f"Repository cloned to: {destination}"
except Exception as e:
return f"Error cloning repository: {e}"
@register_tool(
"github",
{
"type": "function",
"function": {
"name": "read_readme",
"description": "Read README.md from a repository directory.",
"parameters": {
"type": "object",
"properties": {
"repo_dir": {
"type": "string",
"description": "Local directory where repository was cloned.",
},
},
"required": ["repo_dir"],
},
},
},
)
def read_readme(repo_dir: str) -> str:
"""
Read the README.md file inside a GitHub repository.
Workflow:
1. Identify repository directory path.
2. Search for README files with common name patterns.
3. Return file content if found.
"""
try:
repo_path = Path(os.path.expandvars(repo_dir)).expanduser()
if not repo_path.exists():
return f"Error: Repository directory '{repo_dir}' does not exist"
candidates = ["README.md", "readme.md", "Readme.md", "README.MD"]
for filename in candidates:
file_path = repo_path / filename
if file_path.exists():
return file_path.read_text(errors="ignore")
return "No README.md file found in the repository."
except Exception as e:
return f"Error reading README: {e}"
@register_tool(
"github",
{
"type": "function",
"function": {
"name": "list_repo_files",
"description": "Recursively list all files inside a cloned GitHub repository.",
"parameters": {
"type": "object",
"properties": {
"repo_dir": {
"type": "string",
"description": "Path to the local repository folder.",
},
},
"required": ["repo_dir"],
},
},
},
)
def list_repo_files(repo_dir: str) -> str:
"""
Recursively list all files inside a repository.
Workflow:
1. Expand repo path.
2. Walk through directories using Path.rglob().
3. Return file list as newline-separated string.
"""
try:
repo_path = Path(os.path.expandvars(repo_dir)).expanduser()
if not repo_path.exists():
return f"Error: Repository directory '{repo_dir}' does not exist"
files = [str(p) for p in repo_path.rglob("*") if p.is_file()]
if not files:
return "No files found inside repository."
return "\n".join(files)
except Exception as e:
return f"Error listing repository files: {e}"
@register_tool(
"github",
{
"type": "function",
"function": {
"name": "get_file_content",
"description": "Retrieve the content of a file inside a cloned GitHub repository.",
"parameters": {
"type": "object",
"properties": {
"repo_dir": {
"type": "string",
"description": "Local path to the repository.",
},
"relative_path": {
"type": "string",
"description": "Relative path of the file inside the repository.",
},
},
"required": ["repo_dir", "relative_path"],
},
},
},
)
def get_file_content(repo_dir: str, relative_path: str) -> str:
"""
Return the content of a file inside a repository.
Workflow:
1. Compute the absolute file path.
2. Ensure file exists.
3. Read and return the file's content.
"""
try:
repo_path = Path(os.path.expandvars(repo_dir)).expanduser()
file_path = repo_path / relative_path
if not file_path.exists():
return f"Error: File '{relative_path}' does not exist in repository"
return file_path.read_text(errors="ignore")
except Exception as e:
return f"Error reading file: {e}"