mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-20 22:31:48 +00:00
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:
co-authored by
Claude Sonnet 4.6
parent
215b5d40e7
commit
7891fa8854
@@ -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
|
||||
|
||||
@@ -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: [],
|
||||
|
||||
@@ -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
@@ -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
@@ -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" }
|
||||
|
||||
Reference in New Issue
Block a user