Skip to content

Commit 5734ec0

Browse files
feat(plugin): Add Plugin.fetch() for remote plugin fetching and caching (#1647)
Co-authored-by: openhands <[email protected]>
1 parent 74f2b90 commit 5734ec0

File tree

10 files changed

+2587
-80
lines changed

10 files changed

+2587
-80
lines changed

openhands-sdk/openhands/sdk/context/skills/utils.py

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import json
66
import os
77
import re
8-
import shutil
9-
import subprocess
108
from pathlib import Path
119
from typing import TYPE_CHECKING
1210

1311
from fastmcp.mcp_config import MCPConfig
1412

1513
from openhands.sdk.context.skills.exceptions import SkillValidationError
14+
from openhands.sdk.git.cached_repo import try_cached_clone_or_update
1615
from openhands.sdk.logger import get_logger
1716

1817

@@ -316,77 +315,19 @@ def update_skills_repository(
316315
) -> Path | None:
317316
"""Clone or update the local skills repository.
318317
318+
Uses the shared git caching infrastructure from openhands.sdk.git.cached_repo.
319+
When updating, performs: fetch -> checkout ref -> reset --hard to origin/ref.
320+
319321
Args:
320322
repo_url: URL of the skills repository.
321-
branch: Branch name to use.
323+
branch: Branch name to checkout and track.
322324
cache_dir: Directory where the repository should be cached.
323325
324326
Returns:
325327
Path to the local repository if successful, None otherwise.
326328
"""
327329
repo_path = cache_dir / "public-skills"
328-
329-
try:
330-
if repo_path.exists() and (repo_path / ".git").exists():
331-
logger.debug(f"Updating skills repository at {repo_path}")
332-
try:
333-
subprocess.run(
334-
["git", "fetch", "origin"],
335-
cwd=repo_path,
336-
check=True,
337-
capture_output=True,
338-
timeout=30,
339-
)
340-
subprocess.run(
341-
["git", "reset", "--hard", f"origin/{branch}"],
342-
cwd=repo_path,
343-
check=True,
344-
capture_output=True,
345-
timeout=10,
346-
)
347-
logger.debug("Skills repository updated successfully")
348-
except subprocess.TimeoutExpired:
349-
logger.warning("Git pull timed out, using existing cached repository")
350-
except subprocess.CalledProcessError as e:
351-
logger.warning(
352-
f"Failed to update repository: {e.stderr.decode()}, "
353-
f"using existing cached version"
354-
)
355-
else:
356-
logger.info(f"Cloning public skills repository from {repo_url}")
357-
if repo_path.exists():
358-
shutil.rmtree(repo_path)
359-
360-
subprocess.run(
361-
[
362-
"git",
363-
"clone",
364-
"--depth",
365-
"1",
366-
"--branch",
367-
branch,
368-
repo_url,
369-
str(repo_path),
370-
],
371-
check=True,
372-
capture_output=True,
373-
timeout=60,
374-
)
375-
logger.debug(f"Skills repository cloned to {repo_path}")
376-
377-
return repo_path
378-
379-
except subprocess.TimeoutExpired:
380-
logger.warning(f"Git operation timed out for {repo_url}")
381-
return None
382-
except subprocess.CalledProcessError as e:
383-
logger.warning(
384-
f"Failed to clone/update repository {repo_url}: {e.stderr.decode()}"
385-
)
386-
return None
387-
except Exception as e:
388-
logger.warning(f"Error managing skills repository: {str(e)}")
389-
return None
330+
return try_cached_clone_or_update(repo_url, repo_path, ref=branch, update=True)
390331

391332

392333
def discover_skill_resources(skill_dir: Path) -> SkillResources:

0 commit comments

Comments
 (0)