Install the hermes skill to %LOCALAPPDATA% on Windows (#1403)

graphify install --platform hermes always wrote the skill to ~/.hermes/skills,
the POSIX path. On Windows, Hermes scans %LOCALAPPDATA%\hermes\skills, so the
installed skill was never discovered. _platform_skill_destination now has a
hermes branch: Windows -> %LOCALAPPDATA%\hermes\skills, other OSes unchanged
(~/.hermes/skills). Pure path logic — no skillgen regeneration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
safishamsi
2026-06-23 00:18:47 +01:00
co-authored by Claude Opus 4.8
parent 0aeda15c10
commit a4d09aefd8
3 changed files with 28 additions and 0 deletions
+1
View File
@@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu
## Unreleased
- Fix: `graphify install --platform hermes` now installs to the right directory on Windows. Hermes scans `%LOCALAPPDATA%\hermes\skills`, but the installer always used the POSIX `~/.hermes/skills` (so on Windows the skill was never discovered). `_platform_skill_destination` gained a hermes branch that targets `%LOCALAPPDATA%\hermes\skills` on Windows and keeps `~/.hermes/skills` elsewhere (#1403).
- Fix: cross-file type-annotation references no longer create phantom duplicate nodes. A class defined once but referenced via type annotations in N other files (`def f(x: Thing) -> Thing`) produced 1+N nodes — the extra ones with the referencing file's path baked into the id (`pkg_a_py_thing`). `ensure_named_node` minted a *sourced* stub for these cross-file refs, which `_disambiguate_colliding_node_ids` then collided into per-file ids and `_rewire_unique_stub_nodes` refused to collapse. The fallback now emits a *sourceless* stub (like the inheritance-base path), so the references resolve to the single canonical definition. Fixed uniformly across all six language extractors that share the helper (#1402).
- Feat: CUDA (`.cu`/`.cuh`) source files are now extracted. CUDA is a C++ superset, so these files route through the existing C++ (`tree-sitter-cpp`) extractor — no new grammar dependency. `__global__`/`__device__` kernels, host functions, structs and `#include`s are captured, host call edges are inferred, and `<<<grid, block>>>` kernel-launch syntax parses without error. Detection and file-watching follow automatically since both derive their extension sets from the dispatch table / `CODE_EXTENSIONS` (#1411).
+9
View File
@@ -152,6 +152,15 @@ def _platform_skill_destination(platform_name: str, *, project: bool = False, pr
return (project_dir or Path(".")) / ".opencode" / "skills" / "graphify" / "SKILL.md"
return Path.home() / ".config" / "opencode" / "skills" / "graphify" / "SKILL.md"
if platform_name == "hermes":
if project:
return (project_dir or Path(".")) / ".hermes" / "skills" / "graphify" / "SKILL.md"
# On Windows, Hermes scans %LOCALAPPDATA%\hermes\skills, not ~/.hermes (#1403).
if platform.system() == "Windows":
local_appdata = Path(os.environ.get("LOCALAPPDATA") or (Path.home() / "AppData" / "Local"))
return local_appdata / "hermes" / "skills" / "graphify" / "SKILL.md"
return Path.home() / ".hermes" / "skills" / "graphify" / "SKILL.md"
if platform_name == "devin":
if project:
return (project_dir or Path(".")) / ".devin" / "skills" / "graphify" / "SKILL.md"
+18
View File
@@ -992,3 +992,21 @@ def test_uninstall_all_removes_amp_user_skill(tmp_path, monkeypatch):
main()
assert not skill.exists()
def test_hermes_skill_destination_windows_uses_localappdata():
"""#1403: on Windows, Hermes scans %LOCALAPPDATA%\\hermes\\skills, so the global
skill must land there — not ~/.hermes/skills (the POSIX path)."""
from graphify.__main__ import _platform_skill_destination
with patch("graphify.__main__.platform.system", return_value="Windows"), \
patch.dict(os.environ, {"LOCALAPPDATA": str(Path("/tmp/AppDataLocal"))}):
dst = _platform_skill_destination("hermes", project=False)
assert dst == Path("/tmp/AppDataLocal") / "hermes" / "skills" / "graphify" / "SKILL.md", dst
def test_hermes_skill_destination_posix_uses_home():
"""Non-Windows hermes destination is unchanged (~/.hermes/skills)."""
from graphify.__main__ import _platform_skill_destination
with patch("graphify.__main__.platform.system", return_value="Linux"):
dst = _platform_skill_destination("hermes", project=False)
assert str(dst).endswith(".hermes/skills/graphify/SKILL.md"), dst