fix: wiki encoding+collisions, hook rebase guard, detect path resolve, readme gitignore docs

- wiki.py: add encoding="utf-8" to all write_text() calls (fixes Windows cp1252 crash #496)
- wiki.py: deduplicate filenames with _unique_slug() to prevent silent article overwrites (#497)
- hooks.py: skip post-commit/post-checkout during rebase/merge/cherry-pick (#485)
- detect.py: resolve root path at detect() entry so .graphifyignore patterns match consistently (#495)
- README.md: document manifest.json, cost.json gitignore and .graphifyignore platform file examples (#369)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Safi
2026-04-22 06:26:15 +01:00
co-authored by Claude Sonnet 4.6
parent 215b5d40e7
commit 7891fa8854
5 changed files with 46 additions and 6 deletions
+14 -2
View File
@@ -164,8 +164,10 @@ Think of it this way: the always-on hook gives your assistant a map. The `/graph
**Recommended `.gitignore` additions:**
```
# commit graph outputs, ignore the extraction cache
graphify-out/cache/
# keep graph outputs, skip heavy/local-only files
graphify-out/cache/ # optional: commit for shared extraction speed, skip to keep repo small
graphify-out/manifest.json # mtime-based, invalid after git clone — always gitignore this
graphify-out/cost.json # local token tracking, not useful to share
```
**Shared setup:**
@@ -176,6 +178,16 @@ graphify-out/cache/
**Excluding paths** — create `.graphifyignore` in your project root (same syntax as `.gitignore`). Files matching those patterns are skipped during detection and extraction.
```
# .graphifyignore example
AGENTS.md # graphify install files — don't extract your own instructions as knowledge
CLAUDE.md
GEMINI.md
.gemini/
.opencode/
docs/translations/ # generated content you don't want in the graph
```
## Using `graph.json` with an LLM
`graph.json` is not meant to be pasted into a prompt all at once. The useful
+1
View File
@@ -334,6 +334,7 @@ def _is_ignored(path: Path, root: Path, patterns: list[tuple[Path, str]]) -> boo
def detect(root: Path, *, follow_symlinks: bool = False) -> dict:
root = root.resolve()
files: dict[FileType, list[str]] = {
FileType.CODE: [],
FileType.DOCUMENT: [],
+14
View File
@@ -44,6 +44,13 @@ _HOOK_SCRIPT = """\
# Auto-rebuilds the knowledge graph after each commit (code files only, no LLM needed).
# Installed by: graphify hook install
# Skip during rebase/merge/cherry-pick to avoid blocking --continue with unstaged changes
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
[ -d "$GIT_DIR/rebase-merge" ] && exit 0
[ -d "$GIT_DIR/rebase-apply" ] && exit 0
[ -f "$GIT_DIR/MERGE_HEAD" ] && exit 0
[ -f "$GIT_DIR/CHERRY_PICK_HEAD" ] && exit 0
CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only HEAD 2>/dev/null)
if [ -z "$CHANGED" ]; then
exit 0
@@ -93,6 +100,13 @@ if [ ! -d "graphify-out" ]; then
exit 0
fi
# Skip during rebase/merge/cherry-pick
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
[ -d "$GIT_DIR/rebase-merge" ] && exit 0
[ -d "$GIT_DIR/rebase-apply" ] && exit 0
[ -f "$GIT_DIR/MERGE_HEAD" ] && exit 0
[ -f "$GIT_DIR/CHERRY_PICK_HEAD" ] && exit 0
""" + _PYTHON_DETECT + """
echo "[graphify] Branch switched - rebuilding knowledge graph (code files)..."
$GRAPHIFY_PYTHON -c "
+16 -3
View File
@@ -190,12 +190,23 @@ def to_wiki(
god_nodes_data = god_nodes_data or []
count = 0
used_slugs: set[str] = set()
def _unique_slug(base: str) -> str:
slug = base
n = 2
while slug in used_slugs:
slug = f"{base}_{n}"
n += 1
used_slugs.add(slug)
return slug
# Community articles
for cid, nodes in communities.items():
label = labels.get(cid, f"Community {cid}")
article = _community_article(G, cid, nodes, label, labels, cohesion.get(cid))
(out / f"{_safe_filename(label)}.md").write_text(article)
slug = _unique_slug(_safe_filename(label))
(out / f"{slug}.md").write_text(article, encoding="utf-8")
count += 1
# God node articles
@@ -203,12 +214,14 @@ def to_wiki(
nid = node_data.get("id")
if nid and nid in G:
article = _god_node_article(G, nid, labels)
(out / f"{_safe_filename(node_data['label'])}.md").write_text(article)
slug = _unique_slug(_safe_filename(node_data['label']))
(out / f"{slug}.md").write_text(article, encoding="utf-8")
count += 1
# Index
(out / "index.md").write_text(
_index_md(communities, labels, god_nodes_data, G.number_of_nodes(), G.number_of_edges())
_index_md(communities, labels, god_nodes_data, G.number_of_nodes(), G.number_of_edges()),
encoding="utf-8",
)
return count
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "graphifyy"
version = "0.4.25"
version = "0.4.26"
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" }