review-fix(suppress-audit): whatsapp adapter, skill_manager_tool, skill_usage — restore BASE exception semantics

This commit is contained in:
Teknium
2026-09-03 09:42:58 -07:00
parent fe03731efd
commit 812943b3ed
3 changed files with 37 additions and 15 deletions
+7 -5
View File
@@ -80,12 +80,14 @@ def _kill_port_process(port: int) -> None:
if pid <= 0 or not _pid_looks_like_node_bridge(pid):
logger.warning("[whatsapp] Not killing PID %s on port %d: process is not a node bridge (or identity unverifiable)", pid, port)
continue
with suppress(subprocess.SubprocessError, OSError): # ProcessLookupError/PermissionError are OSError subclasses
if not _IS_WINDOWS:
os.kill(pid, signal.SIGTERM)
continue
if _IS_WINDOWS:
from hermes_cli._subprocess_compat import windows_hide_flags
subprocess.run(["taskkill", "/PID", str(pid), "/F"], capture_output=True, stdin=subprocess.DEVNULL, timeout=5, creationflags=windows_hide_flags())
# Only SubprocessError is swallowed per-PID; an OSError (e.g. taskkill missing) aborts the scan.
with suppress(subprocess.SubprocessError):
subprocess.run(["taskkill", "/PID", str(pid), "/F"], capture_output=True, stdin=subprocess.DEVNULL, timeout=5, creationflags=windows_hide_flags())
else:
with suppress(OSError): # ProcessLookupError/PermissionError are OSError subclasses
os.kill(pid, signal.SIGTERM)
def _bridge_pid_is_ours(pid: int, session_path: Path, expected_start) -> bool:
+20 -8
View File
@@ -240,15 +240,27 @@ def _find_skill_in_other_profiles(name: str) -> List[Tuple[str, Path]]:
return matches
_active = _skills_dir()
active_dir = _active.resolve() if _active.exists() else _active
# Every profile's skills dir EXCEPT the active one (already searched).
candidates: List[Tuple[str, Path]] = [("default", root / "skills")]
with suppress(OSError):
if (root / "profiles").is_dir():
candidates += [(e.name, e / "skills") for e in (root / "profiles").iterdir() if e.is_dir()]
# Every profile's skills dir EXCEPT the active one (already searched). A candidate whose
# path cannot be resolved is skipped (not a fatal error); is_dir() checks stay unguarded.
candidates: List[Tuple[str, Path]] = []
with suppress(OSError, RuntimeError):
if (root / "skills").resolve() != active_dir:
candidates.append(("default", root / "skills"))
if (root / "profiles").is_dir():
with suppress(OSError):
for entry in (root / "profiles").iterdir():
if not entry.is_dir():
continue
try:
if (entry / "skills").resolve() == active_dir:
continue
except (OSError, RuntimeError):
continue
candidates.append((entry.name, entry / "skills"))
for profile_name, skills_dir in candidates:
with suppress(OSError, RuntimeError):
if skills_dir.resolve() == active_dir or not skills_dir.is_dir():
continue
if not skills_dir.is_dir():
continue
with suppress(OSError):
hit = next((d for d in _iter_skill_dirs(skills_dir) if d.name == name), None)
if hit is not None:
matches.append((profile_name, hit)) # one match per profile is enough
+10 -2
View File
@@ -264,7 +264,11 @@ def is_curation_eligible(skill_name: str, skill_path: Optional[Path] = None) ->
def _is_curator_managed_record(record: Any) -> bool:
"""``created_by`` is a curator-management OPT-IN flag, not proof of authorship (``curator adopt`` flips it);
the key name is kept because it lives in every user's ``.usage.json``."""
the key name is kept because it lives in every user's ``.usage.json``.
NAMING (issue #67140): the on-disk field is ``created_by``, which reads like provenance but is consumed
as a **curator-management opt-in policy flag**. The two are not the same question:
"""
return isinstance(record, dict) and (record.get("created_by") == "agent" or record.get("agent_created") is True)
@@ -521,7 +525,11 @@ def set_state(skill_name: str, state: str) -> None:
def set_pinned(skill_name: str, pinned: bool) -> bool:
"""False when the write did not land (not curation-eligible)."""
"""False when the write did not land (not curation-eligible).
(skill not curation-eligible), True on success — so callers can report failure instead of a false
success (issue #92993).
"""
return _set_field(skill_name, "pinned", bool(pinned))