fix: skills hub inspect/resolve — 4 bugs
Cherry-picked from PR #2122 by @AtlasMeridia. 1. do_inspect bytes crash: bundle.files returns bytes for official skills, .split() expected str. Added decode guard. 2. GitHub redirects: three httpx.get calls missing follow_redirects=True, causing silent 301 failures on renamed orgs. 3. Skill discovery fallback: scan repo root directories when standard paths (skills/, .agents/skills/, .claude/skills/) miss. 4. tap list KeyError: t['repo'] crashes for local taps. Use safe .get().
This commit is contained in:
parent
306e67f32d
commit
7d0e4510b8
2 changed files with 46 additions and 7 deletions
|
|
@ -375,7 +375,7 @@ class GitHubSource(SkillSource):
|
|||
|
||||
url = f"https://api.github.com/repos/{repo}/contents/{path.rstrip('/')}"
|
||||
try:
|
||||
resp = httpx.get(url, headers=self.auth.get_headers(), timeout=15)
|
||||
resp = httpx.get(url, headers=self.auth.get_headers(), timeout=15, follow_redirects=True)
|
||||
if resp.status_code != 200:
|
||||
return []
|
||||
except httpx.HTTPError:
|
||||
|
|
@ -407,7 +407,7 @@ class GitHubSource(SkillSource):
|
|||
"""Recursively download all text files from a GitHub directory."""
|
||||
url = f"https://api.github.com/repos/{repo}/contents/{path.rstrip('/')}"
|
||||
try:
|
||||
resp = httpx.get(url, headers=self.auth.get_headers(), timeout=15)
|
||||
resp = httpx.get(url, headers=self.auth.get_headers(), timeout=15, follow_redirects=True)
|
||||
if resp.status_code != 200:
|
||||
return {}
|
||||
except httpx.HTTPError:
|
||||
|
|
@ -441,7 +441,7 @@ class GitHubSource(SkillSource):
|
|||
resp = httpx.get(
|
||||
url,
|
||||
headers={**self.auth.get_headers(), "Accept": "application/vnd.github.v3.raw"},
|
||||
timeout=15,
|
||||
timeout=15, follow_redirects=True,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
return resp.text
|
||||
|
|
@ -961,8 +961,8 @@ class SkillsShSource(SkillSource):
|
|||
|
||||
default_repo = f"{parts[0]}/{parts[1]}"
|
||||
repo = detail.get("repo", default_repo) if isinstance(detail, dict) else default_repo
|
||||
skill_token = parts[2]
|
||||
tokens = [skill_token]
|
||||
skill_token=parts[2].split("/")[-1]
|
||||
tokens=[skill_token]
|
||||
if isinstance(detail, dict):
|
||||
tokens.extend([
|
||||
detail.get("install_skill", ""),
|
||||
|
|
@ -970,7 +970,10 @@ class SkillsShSource(SkillSource):
|
|||
detail.get("body_title", ""),
|
||||
])
|
||||
|
||||
for base_path in ("skills/", ".agents/skills/", ".claude/skills/"):
|
||||
# Standard skill paths
|
||||
base_paths = ["skills/", ".agents/skills/", ".claude/skills/"]
|
||||
|
||||
for base_path in base_paths:
|
||||
try:
|
||||
skills = self.github._list_skills_in_repo(repo, base_path)
|
||||
except Exception:
|
||||
|
|
@ -978,6 +981,39 @@ class SkillsShSource(SkillSource):
|
|||
for meta in skills:
|
||||
if self._matches_skill_tokens(meta, tokens):
|
||||
return meta.identifier
|
||||
|
||||
# Fallback: scan repo root for directories that might contain skills
|
||||
try:
|
||||
root_url = f"https://api.github.com/repos/{repo}/contents/"
|
||||
resp = httpx.get(root_url, headers=self.github.auth.get_headers(),
|
||||
timeout=15, follow_redirects=True)
|
||||
if resp.status_code == 200:
|
||||
entries = resp.json()
|
||||
if isinstance(entries, list):
|
||||
for entry in entries:
|
||||
if entry.get("type") != "dir":
|
||||
continue
|
||||
dir_name = entry["name"]
|
||||
if dir_name.startswith(".") or dir_name.startswith("_"):
|
||||
continue
|
||||
if dir_name in ("skills", ".agents", ".claude"):
|
||||
continue # already tried
|
||||
# Try direct: repo/dir/skill_token
|
||||
direct_id = f"{repo}/{dir_name}/{skill_token}"
|
||||
meta = self.github.inspect(direct_id)
|
||||
if meta:
|
||||
return meta.identifier
|
||||
# Try listing skills in this directory
|
||||
try:
|
||||
skills = self.github._list_skills_in_repo(repo, dir_name + "/")
|
||||
except Exception:
|
||||
continue
|
||||
for meta in skills:
|
||||
if self._matches_skill_tokens(meta, tokens):
|
||||
return meta.identifier
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _finalize_inspect_meta(self, meta: SkillMeta, canonical: str, detail: Optional[dict]) -> SkillMeta:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue