graphifyy 0.4.2__tar.gz → 0.4.3__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.3}/PKG-INFO +2 -1
- {graphifyy-0.4.2 → graphifyy-0.4.3}/README.md +1 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/analyze.py +12 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/detect.py +1 -1
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/extract.py +39 -13
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/hooks.py +12 -4
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/watch.py +21 -1
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/PKG-INFO +2 -1
- {graphifyy-0.4.2 → graphifyy-0.4.3}/pyproject.toml +1 -1
- {graphifyy-0.4.2 → graphifyy-0.4.3}/LICENSE +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/__init__.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/__main__.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/benchmark.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/build.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/cache.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/cluster.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/export.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/ingest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/manifest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/report.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/security.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/serve.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-aider.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-claw.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-codex.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-copilot.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-droid.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-opencode.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-trae.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill-windows.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/skill.md +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/transcribe.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/validate.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphify/wiki.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/SOURCES.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/dependency_links.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/entry_points.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/requires.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/graphifyy.egg-info/top_level.txt +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/setup.cfg +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_analyze.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_benchmark.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_build.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_cache.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_claude_md.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_cluster.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_confidence.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_detect.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_export.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_extract.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_hooks.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_hypergraph.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_ingest.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_install.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_languages.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_multilang.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_pipeline.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_rationale.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_report.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_security.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_semantic_similarity.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_serve.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_transcribe.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_validate.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/tests/test_watch.py +0 -0
- {graphifyy-0.4.2 → graphifyy-0.4.3}/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.3
|
|
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,6 +91,7 @@ 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
|
|
|
@@ -6,6 +6,7 @@
|
|
|
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
|
|
|
@@ -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'}
|
|
@@ -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,27 @@ 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("source") not in code_ids and e.get("target") not in code_ids]
|
|
48
|
+
result = {
|
|
49
|
+
"nodes": result["nodes"] + sem_nodes,
|
|
50
|
+
"edges": result["edges"] + sem_edges,
|
|
51
|
+
"hyperedges": existing.get("hyperedges", []),
|
|
52
|
+
"input_tokens": 0,
|
|
53
|
+
"output_tokens": 0,
|
|
54
|
+
}
|
|
55
|
+
except Exception:
|
|
56
|
+
pass # corrupt graph.json - proceed with AST-only
|
|
57
|
+
|
|
37
58
|
detection = {
|
|
38
59
|
"files": {"code": [str(f) for f in code_files], "document": [], "paper": [], "image": []},
|
|
39
60
|
"total_files": len(code_files),
|
|
@@ -48,7 +69,6 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
|
|
|
48
69
|
labels = {cid: "Community " + str(cid) for cid in communities}
|
|
49
70
|
questions = suggest_questions(G, communities, labels)
|
|
50
71
|
|
|
51
|
-
out = watch_path / "graphify-out"
|
|
52
72
|
out.mkdir(exist_ok=True)
|
|
53
73
|
|
|
54
74
|
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.3
|
|
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,6 +91,7 @@ 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
|
|
|
@@ -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.3"
|
|
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
|
|
File without changes
|