mirror of
https://github.com/safishamsi/graphify.git
synced 2026-09-21 13:05:41 +00:00
fix hook reinstall, CRLF labels, skill-windows missing commands (0.3.28)
This commit is contained in:
@@ -2,6 +2,12 @@
|
||||
|
||||
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
|
||||
|
||||
## 0.3.28 (2026-04-10)
|
||||
|
||||
- Fix: hook installers (Claude Code, Codex, Gemini CLI) now always remove and reinstall the hook on re-run — users upgrading from old versions no longer get stuck with a broken hook format (#182)
|
||||
- Fix: rationale node labels no longer contain bare `\r` characters on Windows/WSL CRLF files — breaks Obsidian export was silently producing invalid filenames (#176)
|
||||
- Fix: `skill-windows.md` now includes `--wiki`, `--obsidian-dir`, and `--directed` which were missing vs the main skill (#177)
|
||||
|
||||
## 0.3.27 (2026-04-10)
|
||||
|
||||
- Fix: graphify install --platform gemini now also copies the skill file to ~/.gemini/skills/graphify/SKILL.md so the /graphify trigger works in Gemini CLI (#174)
|
||||
|
||||
+6
-15
@@ -241,10 +241,8 @@ def _install_gemini_hook(project_dir: Path) -> None:
|
||||
except json.JSONDecodeError:
|
||||
settings = {}
|
||||
before_tool = settings.setdefault("hooks", {}).setdefault("BeforeTool", [])
|
||||
if any("graphify" in str(h) for h in before_tool):
|
||||
print(" .gemini/settings.json -> hook already registered (no change)")
|
||||
return
|
||||
before_tool.append(_GEMINI_HOOK)
|
||||
settings["hooks"]["BeforeTool"] = [h for h in before_tool if "graphify" not in str(h)]
|
||||
settings["hooks"]["BeforeTool"].append(_GEMINI_HOOK)
|
||||
settings_path.write_text(json.dumps(settings, indent=2), encoding="utf-8")
|
||||
print(" .gemini/settings.json -> BeforeTool hook registered")
|
||||
|
||||
@@ -455,11 +453,8 @@ def _install_codex_hook(project_dir: Path) -> None:
|
||||
existing = {}
|
||||
|
||||
pre_tool = existing.setdefault("hooks", {}).setdefault("PreToolUse", [])
|
||||
if any("graphify" in str(h) for h in pre_tool):
|
||||
print(f" .codex/hooks.json -> hook already registered (no change)")
|
||||
return
|
||||
|
||||
pre_tool.extend(_CODEX_HOOK["hooks"]["PreToolUse"])
|
||||
existing["hooks"]["PreToolUse"] = [h for h in pre_tool if "graphify" not in str(h)]
|
||||
existing["hooks"]["PreToolUse"].extend(_CODEX_HOOK["hooks"]["PreToolUse"])
|
||||
hooks_path.write_text(json.dumps(existing, indent=2), encoding="utf-8")
|
||||
print(f" .codex/hooks.json -> PreToolUse hook registered")
|
||||
|
||||
@@ -578,12 +573,8 @@ def _install_claude_hook(project_dir: Path) -> None:
|
||||
hooks = settings.setdefault("hooks", {})
|
||||
pre_tool = hooks.setdefault("PreToolUse", [])
|
||||
|
||||
# Check if already installed
|
||||
if any(h.get("matcher") == "Glob|Grep" and "graphify" in str(h) for h in pre_tool):
|
||||
print(f" .claude/settings.json -> hook already registered (no change)")
|
||||
return
|
||||
|
||||
pre_tool.append(_SETTINGS_HOOK)
|
||||
hooks["PreToolUse"] = [h for h in pre_tool if not (h.get("matcher") == "Glob|Grep" 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")
|
||||
|
||||
|
||||
+2
-2
@@ -463,7 +463,7 @@ def to_obsidian(
|
||||
# Map node_id → safe filename so wikilinks stay consistent.
|
||||
# Deduplicate: if two nodes produce the same filename, append a numeric suffix.
|
||||
def safe_name(label: str) -> str:
|
||||
return re.sub(r'[\\/*?:"<>|#^[\]]', "", label).strip() or "unnamed"
|
||||
return re.sub(r'[\\/*?:"<>|#^[\]]', "", label.replace("\r\n", " ").replace("\r", " ").replace("\n", " ")).strip() or "unnamed"
|
||||
|
||||
node_filename: dict[str, str] = {}
|
||||
seen_names: dict[str, int] = {}
|
||||
@@ -699,7 +699,7 @@ def to_canvas(
|
||||
CANVAS_COLORS = ["1", "2", "3", "4", "5", "6"] # red, orange, yellow, green, cyan, purple
|
||||
|
||||
def safe_name(label: str) -> str:
|
||||
return re.sub(r'[\\/*?:"<>|#^[\]]', "", label).strip() or "unnamed"
|
||||
return re.sub(r'[\\/*?:"<>|#^[\]]', "", label.replace("\r\n", " ").replace("\r", " ").replace("\n", " ")).strip() or "unnamed"
|
||||
|
||||
# Build node_filenames if not provided (same dedup logic as to_obsidian)
|
||||
if node_filenames is None:
|
||||
|
||||
+1
-1
@@ -1021,7 +1021,7 @@ def _extract_python_rationale(path: Path, result: dict) -> None:
|
||||
return None
|
||||
|
||||
def _add_rationale(text: str, line: int, parent_nid: str) -> None:
|
||||
label = text[:80].replace("\n", " ").strip()
|
||||
label = text[:80].replace("\r\n", " ").replace("\r", " ").replace("\n", " ").strip()
|
||||
rid = _make_id(stem, "rationale", str(line))
|
||||
if rid not in seen_ids:
|
||||
seen_ids.add(rid)
|
||||
|
||||
@@ -15,6 +15,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti
|
||||
/graphify <path> # full pipeline on specific path
|
||||
/graphify <path> --mode deep # thorough extraction, richer INFERRED edges
|
||||
/graphify <path> --update # incremental - re-extract only new/changed files
|
||||
/graphify <path> --directed # build directed graph (preserves edge direction: source→target)
|
||||
/graphify <path> --cluster-only # rerun clustering on existing graph
|
||||
/graphify <path> --no-viz # skip visualization, just report + JSON
|
||||
/graphify <path> --html # (HTML is generated by default - this flag is a no-op)
|
||||
@@ -22,6 +23,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti
|
||||
/graphify <path> --graphml # export graph.graphml (Gephi, yEd)
|
||||
/graphify <path> --neo4j # generate graphify-out/cypher.txt for Neo4j
|
||||
/graphify <path> --neo4j-push bolt://localhost:7687 # push directly to Neo4j
|
||||
/graphify <path> --wiki # build agent-crawlable wiki (index.md + one article per community)
|
||||
/graphify <path> --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault)
|
||||
/graphify <path> --mcp # start MCP stdio server for agent access
|
||||
/graphify <path> --watch # watch folder, auto-rebuild on code changes (no LLM needed)
|
||||
/graphify add <url> # fetch URL, save to ./raw, update graph
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "graphifyy"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, or images into a queryable knowledge graph"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
|
||||
Reference in New Issue
Block a user