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.
- {graphifyy-0.4.2 → graphifyy-0.4.4}/PKG-INFO +4 -3
- {graphifyy-0.4.2 → graphifyy-0.4.4}/README.md +3 -2
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/__main__.py +1 -1
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/analyze.py +12 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/detect.py +10 -1
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/extract.py +39 -13
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/hooks.py +12 -4
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/watch.py +22 -1
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/PKG-INFO +4 -3
- {graphifyy-0.4.2 → graphifyy-0.4.4}/pyproject.toml +1 -1
- {graphifyy-0.4.2 → graphifyy-0.4.4}/LICENSE +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/__init__.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/benchmark.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/build.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/cache.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/cluster.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/export.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/ingest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/manifest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/report.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/security.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/serve.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-aider.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-claw.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-codex.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-copilot.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-droid.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-opencode.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-trae.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill-windows.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/skill.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/transcribe.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/validate.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphify/wiki.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/SOURCES.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/dependency_links.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/entry_points.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/requires.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/graphifyy.egg-info/top_level.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/setup.cfg +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_analyze.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_benchmark.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_build.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_cache.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_claude_md.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_cluster.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_confidence.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_detect.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_export.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_extract.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_hooks.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_hypergraph.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_ingest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_install.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_languages.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_multilang.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_pipeline.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_rationale.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_report.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_security.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_semantic_similarity.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_serve.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_transcribe.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_validate.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.4}/tests/test_watch.py +0 -0
- {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.
|
|
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
|
[](https://pypi.org/project/graphifyy/)
|
|
92
92
|
[](https://pepy.tech/project/graphifyy)
|
|
93
93
|
[](https://github.com/sponsors/safishamsi)
|
|
94
|
+
[](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.
|
|
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
|
[](https://pypi.org/project/graphifyy/)
|
|
7
7
|
[](https://pepy.tech/project/graphifyy)
|
|
8
8
|
[](https://github.com/sponsors/safishamsi)
|
|
9
|
+
[](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.
|
|
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","
|
|
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)
|
|
116
|
-
|
|
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
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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="
|
|
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.
|
|
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
|
[](https://pypi.org/project/graphifyy/)
|
|
92
92
|
[](https://pepy.tech/project/graphifyy)
|
|
93
93
|
[](https://github.com/sponsors/safishamsi)
|
|
94
|
+
[](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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|