From 189637928371d60148f17c8a4dcca810f573cbde Mon Sep 17 00:00:00 2001 From: Safi Date: Wed, 8 Apr 2026 22:27:08 +0100 Subject: [PATCH] v0.3.16: NetworkX <3.4 compat, .jsx support, pipx follow-up fix Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 6 ++++++ graphify/__main__.py | 6 +++++- graphify/benchmark.py | 5 ++++- graphify/detect.py | 2 +- graphify/extract.py | 1 + graphify/serve.py | 5 ++++- graphify/skill-claw.md | 2 +- graphify/skill-codex.md | 2 +- graphify/skill-droid.md | 2 +- graphify/skill-opencode.md | 2 +- graphify/skill-trae.md | 2 +- graphify/skill.md | 2 +- pyproject.toml | 2 +- 13 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b32ef..5fd2ef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases) +## 0.3.16 (2026-04-08) + +- Fix: `graphify query`, `serve`, and `benchmark` now work on NetworkX < 3.4 — version-safe shim for `node_link_graph()` at all call sites (#95) +- Fix: `.jsx` files now detected and extracted via the JS extractor — added to `CODE_EXTENSIONS` and `_DISPATCH` (#94) +- Fix: `.graphify_python` no longer deleted in Step 9 cleanup across all 6 skill files — pipx users no longer hit `ModuleNotFoundError` on follow-up commands (#92) + ## 0.3.15 (2026-04-08) - Feat: Trae and Trae CN platform support (`graphify install --platform trae` / `trae-cn`) diff --git a/graphify/__main__.py b/graphify/__main__.py index dfd82c4..3dc8f7a 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -502,7 +502,11 @@ def main() -> None: try: import json as _json import networkx as _nx - G = json_graph.node_link_graph(_json.loads(gp.read_text(encoding="utf-8")), edges="links") + _raw = _json.loads(gp.read_text(encoding="utf-8")) + try: + G = json_graph.node_link_graph(_raw, edges="links") + except TypeError: + G = json_graph.node_link_graph(_raw) except Exception as exc: print(f"error: could not load graph: {exc}", file=sys.stderr) sys.exit(1) diff --git a/graphify/benchmark.py b/graphify/benchmark.py index 5d8725a..a71e10e 100644 --- a/graphify/benchmark.py +++ b/graphify/benchmark.py @@ -76,7 +76,10 @@ def run_benchmark( Returns dict with: corpus_tokens, avg_query_tokens, reduction_ratio, per_question """ data = json.loads(Path(graph_path).read_text()) - G = json_graph.node_link_graph(data, edges="links") + try: + G = json_graph.node_link_graph(data, edges="links") + except TypeError: + G = json_graph.node_link_graph(data) if corpus_words is None: # Rough estimate: each node label is ~3 words, plus source context diff --git a/graphify/detect.py b/graphify/detect.py index 9779a8e..108544d 100644 --- a/graphify/detect.py +++ b/graphify/detect.py @@ -17,7 +17,7 @@ class FileType(str, Enum): _MANIFEST_PATH = "graphify-out/manifest.json" -CODE_EXTENSIONS = {'.py', '.ts', '.js', '.tsx', '.go', '.rs', '.java', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.rb', '.swift', '.kt', '.kts', '.cs', '.scala', '.php', '.lua', '.toc', '.zig', '.ps1', '.ex', '.exs', '.m', '.mm'} +CODE_EXTENSIONS = {'.py', '.ts', '.js', '.jsx', '.tsx', '.go', '.rs', '.java', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.rb', '.swift', '.kt', '.kts', '.cs', '.scala', '.php', '.lua', '.toc', '.zig', '.ps1', '.ex', '.exs', '.m', '.mm'} DOC_EXTENSIONS = {'.md', '.txt', '.rst'} PAPER_EXTENSIONS = {'.pdf'} IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'} diff --git a/graphify/extract.py b/graphify/extract.py index f20fc5d..bec3645 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -2362,6 +2362,7 @@ def extract(paths: list[Path]) -> dict: _DISPATCH: dict[str, Any] = { ".py": extract_python, ".js": extract_js, + ".jsx": extract_js, ".ts": extract_js, ".tsx": extract_js, ".go": extract_go, diff --git a/graphify/serve.py b/graphify/serve.py index de1f76c..79bd37f 100644 --- a/graphify/serve.py +++ b/graphify/serve.py @@ -12,7 +12,10 @@ def _load_graph(graph_path: str) -> nx.Graph: try: safe = validate_graph_path(graph_path) data = json.loads(safe.read_text()) - return json_graph.node_link_graph(data, edges="links") + try: + return json_graph.node_link_graph(data, edges="links") + except TypeError: + return json_graph.node_link_graph(data) except (ValueError, FileNotFoundError) as exc: print(f"error: {exc}", file=sys.stderr) sys.exit(1) diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index 887a622..bb04c5e 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -594,7 +594,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json .graphify_python +rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index 78e90cc..6c77f63 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -650,7 +650,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json .graphify_python +rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index de739f6..66a9f1d 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -647,7 +647,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json .graphify_python +rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 93dd212..77e240b 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -646,7 +646,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json .graphify_python +rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 9d77856..58f7bb6 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -625,7 +625,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json .graphify_python +rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/graphify/skill.md b/graphify/skill.md index f6a47fb..2baaa69 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -650,7 +650,7 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.json graphify-out/.graphify_python +rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.json rm -f graphify-out/.needs_update 2>/dev/null || true ``` diff --git a/pyproject.toml b/pyproject.toml index 83715bb..7cf3cb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "graphifyy" -version = "0.3.15" +version = "0.3.16" description = "AI coding assistant skill (Claude Code, Codex, OpenCode, OpenClaw) - turn any folder of code, docs, papers, or images into a queryable knowledge graph" readme = "README.md" license = { file = "LICENSE" }