graphifyy 0.4.2__tar.gz → 0.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {graphifyy-0.4.2 → graphifyy-0.4.4}/PKG-INFO +4 -3
  2. {graphifyy-0.4.2 → graphifyy-0.4.4}/README.md +3 -2
  3. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/__main__.py +1 -1
  4. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/analyze.py +12 -0
  5. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/detect.py +10 -1
  6. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/extract.py +39 -13
  7. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/hooks.py +12 -4
  8. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/watch.py +22 -1
  9. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/PKG-INFO +4 -3
  10. {graphifyy-0.4.2 → graphifyy-0.4.4}/pyproject.toml +1 -1
  11. {graphifyy-0.4.2 → graphifyy-0.4.4}/LICENSE +0 -0
  12. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/__init__.py +0 -0
  13. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/benchmark.py +0 -0
  14. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/build.py +0 -0
  15. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/cache.py +0 -0
  16. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/cluster.py +0 -0
  17. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/export.py +0 -0
  18. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/ingest.py +0 -0
  19. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/manifest.py +0 -0
  20. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/report.py +0 -0
  21. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/security.py +0 -0
  22. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/serve.py +0 -0
  23. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-aider.md +0 -0
  24. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-claw.md +0 -0
  25. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-codex.md +0 -0
  26. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-copilot.md +0 -0
  27. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-droid.md +0 -0
  28. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-opencode.md +0 -0
  29. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-trae.md +0 -0
  30. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-windows.md +0 -0
  31. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill.md +0 -0
  32. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/transcribe.py +0 -0
  33. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/validate.py +0 -0
  34. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/wiki.py +0 -0
  35. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/SOURCES.txt +0 -0
  36. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/dependency_links.txt +0 -0
  37. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/entry_points.txt +0 -0
  38. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/requires.txt +0 -0
  39. {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/top_level.txt +0 -0
  40. {graphifyy-0.4.2 → graphifyy-0.4.4}/setup.cfg +0 -0
  41. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_analyze.py +0 -0
  42. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_benchmark.py +0 -0
  43. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_build.py +0 -0
  44. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_cache.py +0 -0
  45. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_claude_md.py +0 -0
  46. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_cluster.py +0 -0
  47. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_confidence.py +0 -0
  48. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_detect.py +0 -0
  49. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_export.py +0 -0
  50. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_extract.py +0 -0
  51. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_hooks.py +0 -0
  52. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_hypergraph.py +0 -0
  53. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_ingest.py +0 -0
  54. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_install.py +0 -0
  55. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_languages.py +0 -0
  56. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_multilang.py +0 -0
  57. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_pipeline.py +0 -0
  58. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_rationale.py +0 -0
  59. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_report.py +0 -0
  60. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_security.py +0 -0
  61. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_semantic_similarity.py +0 -0
  62. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_serve.py +0 -0
  63. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_transcribe.py +0 -0
  64. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_validate.py +0 -0
  65. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_watch.py +0 -0
  66. {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_wiki.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphifyy
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph
5
5
  License: MIT License
6
6
 
@@ -91,10 +91,11 @@ Dynamic: license-file
91
91
  [![PyPI](https://img.shields.io/pypi/v/graphifyy)](https://pypi.org/project/graphifyy/)
92
92
  [![Downloads](https://static.pepy.tech/badge/graphifyy/month)](https://pepy.tech/project/graphifyy)
93
93
  [![Sponsor](https://img.shields.io/badge/sponsor-safishamsi-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/safishamsi)
94
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-Safi%20Shamsi-0077B5?logo=linkedin)](https://www.linkedin.com/in/safi-shamsi)
94
95
 
95
96
  **An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, Cursor, Gemini CLI, GitHub Copilot CLI, Aider, OpenClaw, Factory Droid, or Trae - it reads your files, builds a knowledge graph, and gives you back structure you didn't know was there. Understand a codebase faster. Find the "why" behind architectural decisions.
96
97
 
97
- Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 20 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia).
98
+ Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 22 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia, Vue, Svelte).
98
99
 
99
100
  > Andrej Karpathy keeps a `/raw` folder where he drops papers, tweets, screenshots, and notes. graphify is the answer to that problem - 71.5x fewer tokens per query vs reading the raw files, persistent across sessions, honest about what it found vs guessed.
100
101
 
@@ -332,7 +333,7 @@ Works with any mix of file types:
332
333
 
333
334
  | Type | Extensions | Extraction |
334
335
  |------|-----------|------------|
335
- | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl` | AST via tree-sitter + call-graph + docstring/comment rationale |
336
+ | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl .vue .svelte` | AST via tree-sitter + call-graph + docstring/comment rationale |
336
337
  | Docs | `.md .txt .rst` | Concepts + relationships + design rationale via Claude |
337
338
  | Office | `.docx .xlsx` | Converted to markdown then extracted via Claude (requires `pip install graphifyy[office]`) |
338
339
  | Papers | `.pdf` | Citation mining + concept extraction |
@@ -6,10 +6,11 @@
6
6
  [![PyPI](https://img.shields.io/pypi/v/graphifyy)](https://pypi.org/project/graphifyy/)
7
7
  [![Downloads](https://static.pepy.tech/badge/graphifyy/month)](https://pepy.tech/project/graphifyy)
8
8
  [![Sponsor](https://img.shields.io/badge/sponsor-safishamsi-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/safishamsi)
9
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-Safi%20Shamsi-0077B5?logo=linkedin)](https://www.linkedin.com/in/safi-shamsi)
9
10
 
10
11
  **An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, Cursor, Gemini CLI, GitHub Copilot CLI, Aider, OpenClaw, Factory Droid, or Trae - it reads your files, builds a knowledge graph, and gives you back structure you didn't know was there. Understand a codebase faster. Find the "why" behind architectural decisions.
11
12
 
12
- Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 20 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia).
13
+ Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 22 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia, Vue, Svelte).
13
14
 
14
15
  > Andrej Karpathy keeps a `/raw` folder where he drops papers, tweets, screenshots, and notes. graphify is the answer to that problem - 71.5x fewer tokens per query vs reading the raw files, persistent across sessions, honest about what it found vs guessed.
15
16
 
@@ -247,7 +248,7 @@ Works with any mix of file types:
247
248
 
248
249
  | Type | Extensions | Extraction |
249
250
  |------|-----------|------------|
250
- | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl` | AST via tree-sitter + call-graph + docstring/comment rationale |
251
+ | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl .vue .svelte` | AST via tree-sitter + call-graph + docstring/comment rationale |
251
252
  | Docs | `.md .txt .rst` | Concepts + relationships + design rationale via Claude |
252
253
  | Office | `.docx .xlsx` | Converted to markdown then extracted via Claude (requires `pip install graphifyy[office]`) |
253
254
  | Papers | `.pdf` | Citation mining + concept extraction |
@@ -428,7 +428,7 @@ _CODEX_HOOK = {
428
428
  "type": "command",
429
429
  "command": (
430
430
  "[ -f graphify-out/graph.json ] && "
431
- r"""echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"},"systemMessage":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}' """
431
+ r"""echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}}' """
432
432
  "|| true"
433
433
  ),
434
434
  }
@@ -218,7 +218,11 @@ def _cross_file_surprises(G: nx.Graph, communities: dict[int, list[str]], top_n:
218
218
 
219
219
  score, reasons = _surprise_score(G, u, v, data, node_community, u_source, v_source)
220
220
  src_id = data.get("_src", u)
221
+ if src_id not in G.nodes:
222
+ src_id = u
221
223
  tgt_id = data.get("_tgt", v)
224
+ if tgt_id not in G.nodes:
225
+ tgt_id = v
222
226
  candidates.append({
223
227
  "_score": score,
224
228
  "source": G.nodes[src_id].get("label", src_id),
@@ -294,7 +298,11 @@ def _cross_community_surprises(
294
298
  # This edge crosses community boundaries - interesting
295
299
  confidence = data.get("confidence", "EXTRACTED")
296
300
  src_id = data.get("_src", u)
301
+ if src_id not in G.nodes:
302
+ src_id = u
297
303
  tgt_id = data.get("_tgt", v)
304
+ if tgt_id not in G.nodes:
305
+ tgt_id = v
298
306
  surprises.append({
299
307
  "source": G.nodes[src_id].get("label", src_id),
300
308
  "target": G.nodes[tgt_id].get("label", tgt_id),
@@ -392,7 +400,11 @@ def suggest_questions(
392
400
  others = []
393
401
  for u, v, d in inferred[:2]:
394
402
  src_id = d.get("_src", u)
403
+ if src_id not in G.nodes:
404
+ src_id = u
395
405
  tgt_id = d.get("_tgt", v)
406
+ if tgt_id not in G.nodes:
407
+ tgt_id = v
396
408
  other_id = tgt_id if src_id == node_id else src_id
397
409
  others.append(G.nodes[other_id].get("label", other_id))
398
410
  questions.append({
@@ -18,7 +18,7 @@ class FileType(str, Enum):
18
18
 
19
19
  _MANIFEST_PATH = "graphify-out/manifest.json"
20
20
 
21
- 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', '.jl'}
21
+ 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', '.jl', '.vue', '.svelte'}
22
22
  DOC_EXTENSIONS = {'.md', '.txt', '.rst'}
23
23
  PAPER_EXTENSIONS = {'.pdf'}
24
24
  IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'}
@@ -241,6 +241,13 @@ _SKIP_DIRS = {
241
241
  ".tox", ".eggs", "*.egg-info",
242
242
  }
243
243
 
244
+ # Large generated files that are never useful to extract
245
+ _SKIP_FILES = {
246
+ "package-lock.json", "yarn.lock", "pnpm-lock.yaml",
247
+ "Cargo.lock", "poetry.lock", "Gemfile.lock",
248
+ "composer.lock", "go.sum", "go.work.sum",
249
+ }
250
+
244
251
  def _is_noise_dir(part: str) -> bool:
245
252
  """Return True if this directory name looks like a venv, cache, or dep dir."""
246
253
  if part in _SKIP_DIRS:
@@ -357,6 +364,8 @@ def detect(root: Path, *, follow_symlinks: bool = False) -> dict:
357
364
  and not _is_ignored(dp / d, root, ignore_patterns)
358
365
  ]
359
366
  for fname in filenames:
367
+ if fname in _SKIP_FILES:
368
+ continue
360
369
  p = dp / fname
361
370
  if p not in seen:
362
371
  seen.add(p)
@@ -112,8 +112,18 @@ def _import_python(node, source: bytes, file_nid: str, stem: str, edges: list, s
112
112
  elif t == "import_from_statement":
113
113
  module_node = node.child_by_field_name("module_name")
114
114
  if module_node:
115
- raw = _read_text(module_node, source).lstrip(".")
116
- tgt_nid = _make_id(raw)
115
+ raw = _read_text(module_node, source)
116
+ if raw.startswith("."):
117
+ # Relative import - resolve to full path so IDs match file node IDs
118
+ dots = len(raw) - len(raw.lstrip("."))
119
+ module_name = raw.lstrip(".")
120
+ base = Path(str_path).parent
121
+ for _ in range(dots - 1):
122
+ base = base.parent
123
+ rel = (module_name.replace(".", "/") + ".py") if module_name else "__init__.py"
124
+ tgt_nid = _make_id(str(base / rel))
125
+ else:
126
+ tgt_nid = _make_id(raw)
117
127
  edges.append({
118
128
  "source": file_nid,
119
129
  "target": tgt_nid,
@@ -129,18 +139,32 @@ def _import_js(node, source: bytes, file_nid: str, stem: str, edges: list, str_p
129
139
  for child in node.children:
130
140
  if child.type == "string":
131
141
  raw = _read_text(child, source).strip("'\"` ")
132
- module_name = raw.lstrip("./").split("/")[-1]
133
- if module_name:
142
+ if not raw:
143
+ break
144
+ if raw.startswith("."):
145
+ # Relative import - resolve to full path so IDs match file node IDs
146
+ resolved = Path(str_path).parent / raw
147
+ # TypeScript ESM: imports written as .js but actual file is .ts/.tsx
148
+ if resolved.suffix == ".js":
149
+ resolved = resolved.with_suffix(".ts")
150
+ elif resolved.suffix == ".jsx":
151
+ resolved = resolved.with_suffix(".tsx")
152
+ tgt_nid = _make_id(str(resolved))
153
+ else:
154
+ # Bare/scoped import (node_modules) - use last segment; dropped as external
155
+ module_name = raw.split("/")[-1]
156
+ if not module_name:
157
+ break
134
158
  tgt_nid = _make_id(module_name)
135
- edges.append({
136
- "source": file_nid,
137
- "target": tgt_nid,
138
- "relation": "imports_from",
139
- "confidence": "EXTRACTED",
140
- "source_file": str_path,
141
- "source_location": f"L{node.start_point[0] + 1}",
142
- "weight": 1.0,
143
- })
159
+ edges.append({
160
+ "source": file_nid,
161
+ "target": tgt_nid,
162
+ "relation": "imports_from",
163
+ "confidence": "EXTRACTED",
164
+ "source_file": str_path,
165
+ "source_location": f"L{node.start_point[0] + 1}",
166
+ "weight": 1.0,
167
+ })
144
168
  break
145
169
 
146
170
 
@@ -2622,6 +2646,8 @@ def extract(paths: list[Path]) -> dict:
2622
2646
  ".m": extract_objc,
2623
2647
  ".mm": extract_objc,
2624
2648
  ".jl": extract_julia,
2649
+ ".vue": extract_js,
2650
+ ".svelte": extract_js,
2625
2651
  }
2626
2652
 
2627
2653
  total = len(paths)
@@ -20,13 +20,21 @@ if [ -n "$GRAPHIFY_BIN" ]; then
20
20
  # Allowlist: only keep characters valid in a filesystem path to prevent
21
21
  # injection if the shebang contains shell metacharacters
22
22
  case "$GRAPHIFY_PYTHON" in
23
- *[!a-zA-Z0-9/_.-]*) GRAPHIFY_PYTHON="python3" ;;
23
+ *[!a-zA-Z0-9/_.-]*) GRAPHIFY_PYTHON="" ;;
24
24
  esac
25
- if ! "$GRAPHIFY_PYTHON" -c "import graphify" 2>/dev/null; then
25
+ if [ -n "$GRAPHIFY_PYTHON" ] && ! "$GRAPHIFY_PYTHON" -c "import graphify" 2>/dev/null; then
26
+ GRAPHIFY_PYTHON=""
27
+ fi
28
+ fi
29
+ # Fall back: try python3, then python (Windows has no python3 shim)
30
+ if [ -z "$GRAPHIFY_PYTHON" ]; then
31
+ if command -v python3 >/dev/null 2>&1 && python3 -c "import graphify" 2>/dev/null; then
26
32
  GRAPHIFY_PYTHON="python3"
33
+ elif command -v python >/dev/null 2>&1 && python -c "import graphify" 2>/dev/null; then
34
+ GRAPHIFY_PYTHON="python"
35
+ else
36
+ exit 0
27
37
  fi
28
- else
29
- GRAPHIFY_PYTHON="python3"
30
38
  fi
31
39
  """
32
40
 
@@ -34,6 +34,28 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
34
34
 
35
35
  result = extract(code_files)
36
36
 
37
+ # Preserve semantic nodes/edges from a previous full run.
38
+ # AST-only rebuild replaces code nodes; doc/paper/image nodes are kept.
39
+ out = watch_path / "graphify-out"
40
+ existing_graph = out / "graph.json"
41
+ if existing_graph.exists():
42
+ try:
43
+ existing = json.loads(existing_graph.read_text(encoding="utf-8"))
44
+ code_ids = {n["id"] for n in existing.get("nodes", []) if n.get("file_type") == "code"}
45
+ sem_nodes = [n for n in existing.get("nodes", []) if n.get("file_type") != "code"]
46
+ sem_edges = [e for e in existing.get("edges", [])
47
+ if e.get("confidence") in ("INFERRED", "AMBIGUOUS")
48
+ or (e.get("source") not in code_ids and e.get("target") not in code_ids)]
49
+ result = {
50
+ "nodes": result["nodes"] + sem_nodes,
51
+ "edges": result["edges"] + sem_edges,
52
+ "hyperedges": existing.get("hyperedges", []),
53
+ "input_tokens": 0,
54
+ "output_tokens": 0,
55
+ }
56
+ except Exception:
57
+ pass # corrupt graph.json - proceed with AST-only
58
+
37
59
  detection = {
38
60
  "files": {"code": [str(f) for f in code_files], "document": [], "paper": [], "image": []},
39
61
  "total_files": len(code_files),
@@ -48,7 +70,6 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
48
70
  labels = {cid: "Community " + str(cid) for cid in communities}
49
71
  questions = suggest_questions(G, communities, labels)
50
72
 
51
- out = watch_path / "graphify-out"
52
73
  out.mkdir(exist_ok=True)
53
74
 
54
75
  report = generate(G, communities, cohesion, labels, gods, surprises, detection,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphifyy
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph
5
5
  License: MIT License
6
6
 
@@ -91,10 +91,11 @@ Dynamic: license-file
91
91
  [![PyPI](https://img.shields.io/pypi/v/graphifyy)](https://pypi.org/project/graphifyy/)
92
92
  [![Downloads](https://static.pepy.tech/badge/graphifyy/month)](https://pepy.tech/project/graphifyy)
93
93
  [![Sponsor](https://img.shields.io/badge/sponsor-safishamsi-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/safishamsi)
94
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-Safi%20Shamsi-0077B5?logo=linkedin)](https://www.linkedin.com/in/safi-shamsi)
94
95
 
95
96
  **An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, Cursor, Gemini CLI, GitHub Copilot CLI, Aider, OpenClaw, Factory Droid, or Trae - it reads your files, builds a knowledge graph, and gives you back structure you didn't know was there. Understand a codebase faster. Find the "why" behind architectural decisions.
96
97
 
97
- Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 20 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia).
98
+ Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, images in other languages, or video and audio files - graphify extracts concepts and relationships from all of it and connects them into one graph. Videos are transcribed with Whisper using a domain-aware prompt derived from your corpus. 22 languages supported via tree-sitter AST (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig, PowerShell, Elixir, Objective-C, Julia, Vue, Svelte).
98
99
 
99
100
  > Andrej Karpathy keeps a `/raw` folder where he drops papers, tweets, screenshots, and notes. graphify is the answer to that problem - 71.5x fewer tokens per query vs reading the raw files, persistent across sessions, honest about what it found vs guessed.
100
101
 
@@ -332,7 +333,7 @@ Works with any mix of file types:
332
333
 
333
334
  | Type | Extensions | Extraction |
334
335
  |------|-----------|------------|
335
- | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl` | AST via tree-sitter + call-graph + docstring/comment rationale |
336
+ | Code | `.py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1 .ex .exs .m .mm .jl .vue .svelte` | AST via tree-sitter + call-graph + docstring/comment rationale |
336
337
  | Docs | `.md .txt .rst` | Concepts + relationships + design rationale via Claude |
337
338
  | Office | `.docx .xlsx` | Converted to markdown then extracted via Claude (requires `pip install graphifyy[office]`) |
338
339
  | Papers | `.pdf` | Citation mining + concept extraction |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "graphifyy"
7
- version = "0.4.2"
7
+ version = "0.4.4"
8
8
  description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes