diff --git a/README.md b/README.md index 67110208..72163f90 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/graphify/detect.py b/graphify/detect.py index d67d2f2f..39262587 100644 --- a/graphify/detect.py +++ b/graphify/detect.py @@ -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: [], diff --git a/graphify/hooks.py b/graphify/hooks.py index 2a79ec89..6e0155f1 100644 --- a/graphify/hooks.py +++ b/graphify/hooks.py @@ -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 " diff --git a/graphify/wiki.py b/graphify/wiki.py index 732444f7..6b2f5f95 100644 --- a/graphify/wiki.py +++ b/graphify/wiki.py @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 0e6c8b6e..5ffee074 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" }