From 81770d5a63bee8ab332aa6d586eb68b6e837f315 Mon Sep 17 00:00:00 2001 From: LeonSGP43 <154585401+LeonSGP43@users.noreply.github.com> Date: Thu, 23 Apr 2026 02:39:06 +0800 Subject: [PATCH] fix(skills): hash byte-backed bundle files --- tests/tools/test_skills_hub.py | 25 +++++++++++++++++++++++++ tools/skills_hub.py | 6 +++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/tools/test_skills_hub.py b/tests/tools/test_skills_hub.py index 24d1e87affcc8..ddabec05b9d17 100644 --- a/tests/tools/test_skills_hub.py +++ b/tests/tools/test_skills_hub.py @@ -695,6 +695,31 @@ def test_bundle_content_hash_matches_installed_content_hash(self, tmp_path): assert bundle_content_hash(bundle) == content_hash(skill_dir) + def test_bundle_content_hash_accepts_bytes_content(self): + text_bundle = SkillBundle( + name="demo-skill", + files={ + "SKILL.md": "same content", + "references/checklist.md": "- [ ] security\n", + }, + source="github", + identifier="owner/repo/demo-skill", + trust_level="community", + ) + + bytes_bundle = SkillBundle( + name="demo-skill", + files={ + "SKILL.md": b"same content", + "references/checklist.md": b"- [ ] security\n", + }, + source="github", + identifier="owner/repo/demo-skill", + trust_level="community", + ) + + assert bundle_content_hash(bytes_bundle) == bundle_content_hash(text_bundle) + def test_reports_update_when_remote_hash_differs(self): lock = MagicMock() lock.list_installed.return_value = [{ diff --git a/tools/skills_hub.py b/tools/skills_hub.py index 47aef8075b7c1..d91414160a864 100644 --- a/tools/skills_hub.py +++ b/tools/skills_hub.py @@ -2630,7 +2630,11 @@ def bundle_content_hash(bundle: SkillBundle) -> str: """Compute a deterministic hash for an in-memory skill bundle.""" h = hashlib.sha256() for rel_path in sorted(bundle.files): - h.update(bundle.files[rel_path].encode("utf-8")) + content = bundle.files[rel_path] + if isinstance(content, bytes): + h.update(content) + else: + h.update(content.encode("utf-8")) return f"sha256:{h.hexdigest()[:16]}"