Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions tools/skills_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ def _read_cache(self, key: str) -> Optional[list]:
stat = cache_file.stat()
if time.time() - stat.st_mtime > INDEX_CACHE_TTL:
return None
return json.loads(cache_file.read_text())
return json.loads(cache_file.read_text(encoding="utf-8"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reader-only change does not create a UTF-8 round trip: its paired writer still calls write_text(json.dumps(..., ensure_ascii=False)) without encoding="utf-8". On a non-UTF-8 Windows locale it can write locale bytes (or fail for unrepresentable characters), and this UTF-8 reader can then raise UnicodeDecodeError, which the surrounding handler does not catch.

except (OSError, json.JSONDecodeError):
return None

Expand Down Expand Up @@ -3231,7 +3231,7 @@ def _read_index_cache(key: str) -> Optional[Any]:
stat = cache_file.stat()
if time.time() - stat.st_mtime > INDEX_CACHE_TTL:
return None
return json.loads(cache_file.read_text())
return json.loads(cache_file.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return None

Expand Down Expand Up @@ -3285,7 +3285,7 @@ def load(self) -> dict:
if not self.path.exists():
return {"version": 1, "installed": {}}
try:
return json.loads(self.path.read_text())
return json.loads(self.path.read_text(encoding="utf-8"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HubLockFile.save() still writes ensure_ascii=False JSON without an explicit encoding, so making only this consumer UTF-8-only breaks the producer/consumer encoding contract. Update the paired writer and cover a non-ASCII lock entry round trip.

except (json.JSONDecodeError, OSError):
return {"version": 1, "installed": {}}

Expand Down Expand Up @@ -3357,7 +3357,7 @@ def load(self) -> List[dict]:
if not self.path.exists():
return []
try:
data = json.loads(self.path.read_text())
data = json.loads(self.path.read_text(encoding="utf-8"))
return data.get("taps", [])
except (json.JSONDecodeError, OSError):
return []
Expand Down Expand Up @@ -3675,7 +3675,7 @@ def _load_hermes_index() -> Optional[dict]:
try:
age = time.time() - hermes_index_cache_file.stat().st_mtime
if age < HERMES_INDEX_TTL:
return json.loads(hermes_index_cache_file.read_text())
return json.loads(hermes_index_cache_file.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
pass

Expand Down Expand Up @@ -3741,7 +3741,7 @@ def _load_stale_index_cache() -> Optional[dict]:
hermes_index_cache_file = _hermes_index_cache_file()
if hermes_index_cache_file.exists():
try:
return json.loads(hermes_index_cache_file.read_text())
return json.loads(hermes_index_cache_file.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
pass
return None
Expand Down
2 changes: 1 addition & 1 deletion tools/skills_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def _backfill_optional_provenance(quiet: bool = False) -> List[str]:

lock_path = SKILLS_DIR / ".hub" / "lock.json"
try:
data = json.loads(lock_path.read_text()) if lock_path.exists() else {"version": 1, "installed": {}}
data = json.loads(lock_path.read_text(encoding="utf-8")) if lock_path.exists() else {"version": 1, "installed": {}}
except (json.JSONDecodeError, OSError):
data = {"version": 1, "installed": {}}
installed = data.setdefault("installed", {})
Expand Down
Loading