mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-12 18:37:12 +00:00
Fix PreToolUse hook for Claude Code v2.1.117+ (Glob|Grep → Bash matcher)
Grep and Glob tools removed in CC v2.1.117; searches now go through Bash. Hook now reads stdin tool_input and pattern-matches on search commands. Uninstall/reinstall handles both old and new matcher for clean upgrades. Closes #578 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,10 @@ dist/
|
||||
|
||||
Same syntax as `.gitignore`. You can keep a single `.graphifyignore` at your repo root — patterns work correctly even when graphify is run on a subfolder.
|
||||
|
||||
## What's new in v0.5.2
|
||||
|
||||
- **Hook fix for Claude Code v2.1.117+** — the PreToolUse hook now matches on `Bash` instead of `Glob|Grep`. Claude Code v2.1.117 removed dedicated Grep/Glob tools; searches now go through Bash. The hook inspects the command string and only fires on search-like calls (grep, rg, find, fd etc.), so it does not trigger on every shell command.
|
||||
|
||||
## What's new in v0.5.1
|
||||
|
||||
- **Node ID collision fix** — files sharing the same name in different directories (e.g. two `utils.py` files) now get unique IDs by prefixing the parent directory name.
|
||||
|
||||
+14
-6
@@ -37,14 +37,22 @@ def _refresh_all_version_stamps() -> None:
|
||||
vf.write_text(__version__, encoding="utf-8")
|
||||
|
||||
_SETTINGS_HOOK = {
|
||||
"matcher": "Glob|Grep",
|
||||
# Claude Code v2.1.117+ removed dedicated Grep/Glob tools; searches now go through Bash.
|
||||
# We match on Bash and inspect the command string to avoid firing on every shell call.
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": (
|
||||
"[ -f graphify-out/graph.json ] && "
|
||||
r"""echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}}' """
|
||||
"|| true"
|
||||
"CMD=$(python3 -c \""
|
||||
"import json,sys; d=json.load(sys.stdin); "
|
||||
"print(d.get('tool_input',d).get('command',''))\" 2>/dev/null || true); "
|
||||
"case \"$CMD\" in "
|
||||
"*grep*|*rg\ *|*ripgrep*|*find\ *|*fd\ *|*ack\ *|*ag\ *) "
|
||||
" [ -f graphify-out/graph.json ] && "
|
||||
r""" echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}}' """
|
||||
" || true ;; "
|
||||
"esac"
|
||||
),
|
||||
}
|
||||
],
|
||||
@@ -857,7 +865,7 @@ def _install_claude_hook(project_dir: Path) -> None:
|
||||
hooks = settings.setdefault("hooks", {})
|
||||
pre_tool = hooks.setdefault("PreToolUse", [])
|
||||
|
||||
hooks["PreToolUse"] = [h for h in pre_tool if not (h.get("matcher") == "Glob|Grep" and "graphify" in str(h))]
|
||||
hooks["PreToolUse"] = [h for h in pre_tool if not (h.get("matcher") in ("Glob|Grep", "Bash") and "graphify" in str(h))]
|
||||
hooks["PreToolUse"].append(_SETTINGS_HOOK)
|
||||
settings_path.write_text(json.dumps(settings, indent=2), encoding="utf-8")
|
||||
print(f" .claude/settings.json -> PreToolUse hook registered")
|
||||
@@ -873,7 +881,7 @@ def _uninstall_claude_hook(project_dir: Path) -> None:
|
||||
except json.JSONDecodeError:
|
||||
return
|
||||
pre_tool = settings.get("hooks", {}).get("PreToolUse", [])
|
||||
filtered = [h for h in pre_tool if not (h.get("matcher") == "Glob|Grep" and "graphify" in str(h))]
|
||||
filtered = [h for h in pre_tool if not (h.get("matcher") in ("Glob|Grep", "Bash") and "graphify" in str(h))]
|
||||
if len(filtered) == len(pre_tool):
|
||||
return
|
||||
settings["hooks"]["PreToolUse"] = filtered
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "graphifyy"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, Gemini CLI, Aider, OpenClaw, Factory Droid, Trae, Hermes, Kiro, Google Antigravity) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
|
||||
@@ -109,7 +109,7 @@ def test_install_creates_settings_json(tmp_path):
|
||||
assert settings_path.exists()
|
||||
settings = json.loads(settings_path.read_text())
|
||||
hooks = settings.get("hooks", {}).get("PreToolUse", [])
|
||||
assert any("Glob|Grep" in h.get("matcher", "") for h in hooks)
|
||||
assert any(h.get("matcher") == "Bash" for h in hooks)
|
||||
|
||||
|
||||
def test_install_settings_json_idempotent(tmp_path):
|
||||
@@ -120,8 +120,8 @@ def test_install_settings_json_idempotent(tmp_path):
|
||||
settings_path = tmp_path / ".claude" / "settings.json"
|
||||
settings = json.loads(settings_path.read_text())
|
||||
hooks = settings.get("hooks", {}).get("PreToolUse", [])
|
||||
glob_grep_hooks = [h for h in hooks if "Glob|Grep" in h.get("matcher", "")]
|
||||
assert len(glob_grep_hooks) == 1
|
||||
bash_hooks = [h for h in hooks if h.get("matcher") == "Bash" and "graphify" in str(h)]
|
||||
assert len(bash_hooks) == 1
|
||||
|
||||
|
||||
def test_uninstall_removes_settings_hook(tmp_path):
|
||||
@@ -133,4 +133,4 @@ def test_uninstall_removes_settings_hook(tmp_path):
|
||||
if settings_path.exists():
|
||||
settings = json.loads(settings_path.read_text())
|
||||
hooks = settings.get("hooks", {}).get("PreToolUse", [])
|
||||
assert not any("Glob|Grep" in h.get("matcher", "") for h in hooks)
|
||||
assert not any(h.get("matcher") == "Bash" and "graphify" in str(h) for h in hooks)
|
||||
|
||||
Reference in New Issue
Block a user