mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-13 10:57:13 +00:00
Fix four bugs from community PRs
- cache: skip directory source_file in save_cached to prevent IsADirectoryError (#444) - report: skip structural-only communities with no real nodes (#443) - hooks: allow @ in python path allowlist for Homebrew paths (#474) - watch: keep source_file paths project-relative after rebuild (#434) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+8
-1
@@ -75,8 +75,15 @@ def save_cached(path: Path, result: dict, root: Path = Path(".")) -> None:
|
||||
|
||||
Stores as graphify-out/cache/{hash}.json where hash = SHA256 of current file contents.
|
||||
result should be a dict with 'nodes' and 'edges' lists.
|
||||
|
||||
No-ops if `path` is not a regular file. Subagent-produced semantic fragments
|
||||
occasionally carry a directory path in `source_file`; skipping them prevents
|
||||
IsADirectoryError from aborting the whole batch.
|
||||
"""
|
||||
h = file_hash(path, root)
|
||||
p = Path(path)
|
||||
if not p.is_file():
|
||||
return
|
||||
h = file_hash(p, root)
|
||||
entry = cache_dir(root) / f"{h}.json"
|
||||
tmp = entry.with_suffix(".tmp")
|
||||
try:
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ if [ -n "$GRAPHIFY_BIN" ]; then
|
||||
# Allowlist: only keep characters valid in a filesystem path to prevent
|
||||
# injection if the shebang contains shell metacharacters
|
||||
case "$GRAPHIFY_PYTHON" in
|
||||
*[!a-zA-Z0-9/_.-]*) GRAPHIFY_PYTHON="" ;;
|
||||
*[!a-zA-Z0-9/_.@-]*) GRAPHIFY_PYTHON="" ;;
|
||||
esac
|
||||
if [ -n "$GRAPHIFY_PYTHON" ] && ! "$GRAPHIFY_PYTHON" -c "import graphify" 2>/dev/null; then
|
||||
GRAPHIFY_PYTHON=""
|
||||
|
||||
@@ -111,6 +111,8 @@ def generate(
|
||||
score = cohesion_scores.get(cid, 0.0)
|
||||
# Filter method/function stubs from display - they're structural noise
|
||||
real_nodes = [n for n in nodes if not _ifn(G, n)]
|
||||
if not real_nodes:
|
||||
continue
|
||||
display = [G.nodes[n].get("label", n) for n in real_nodes[:8]]
|
||||
suffix = f" (+{len(real_nodes)-8} more)" if len(real_nodes) > 8 else ""
|
||||
lines += [
|
||||
|
||||
+28
-2
@@ -12,11 +12,35 @@ _WATCHED_EXTENSIONS = CODE_EXTENSIONS | DOC_EXTENSIONS | PAPER_EXTENSIONS | IMAG
|
||||
_CODE_EXTENSIONS = CODE_EXTENSIONS
|
||||
|
||||
|
||||
def _report_root_label(watch_path: Path) -> str:
|
||||
if watch_path.is_absolute():
|
||||
return watch_path.name or str(watch_path)
|
||||
return Path.cwd().name if watch_path == Path(".") else str(watch_path)
|
||||
|
||||
|
||||
def _relativize_source_files(payload: dict, root: Path) -> None:
|
||||
for bucket in ("nodes", "edges", "hyperedges"):
|
||||
for item in payload.get(bucket, []):
|
||||
source = item.get("source_file")
|
||||
if not source:
|
||||
continue
|
||||
source_path = Path(source)
|
||||
if not source_path.is_absolute():
|
||||
continue
|
||||
try:
|
||||
item["source_file"] = str(source_path.resolve().relative_to(root))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
|
||||
def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
|
||||
"""Re-run AST extraction + build + cluster + report for code files. No LLM needed.
|
||||
|
||||
Returns True on success, False on error.
|
||||
"""
|
||||
watch_root = watch_path.resolve()
|
||||
project_root = Path.cwd().resolve() if not watch_path.is_absolute() else watch_root
|
||||
report_root = _report_root_label(watch_path)
|
||||
try:
|
||||
from graphify.extract import extract
|
||||
from graphify.detect import detect
|
||||
@@ -33,7 +57,7 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
|
||||
print("[graphify watch] No code files found - nothing to rebuild.")
|
||||
return False
|
||||
|
||||
result = extract(code_files, cache_root=watch_path)
|
||||
result = extract(code_files, cache_root=watch_root)
|
||||
|
||||
# Preserve semantic nodes/edges from a previous full run.
|
||||
# AST-only rebuild replaces code nodes; doc/paper/image nodes are kept.
|
||||
@@ -57,6 +81,8 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
|
||||
except Exception:
|
||||
pass # corrupt graph.json - proceed with AST-only
|
||||
|
||||
_relativize_source_files(result, project_root)
|
||||
|
||||
detection = {
|
||||
"files": {"code": [str(f) for f in code_files], "document": [], "paper": [], "image": []},
|
||||
"total_files": len(code_files),
|
||||
@@ -74,7 +100,7 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
|
||||
out.mkdir(exist_ok=True)
|
||||
|
||||
report = generate(G, communities, cohesion, labels, gods, surprises, detection,
|
||||
{"input": 0, "output": 0}, str(watch_path), suggested_questions=questions)
|
||||
{"input": 0, "output": 0}, report_root, suggested_questions=questions)
|
||||
(out / "GRAPH_REPORT.md").write_text(report, encoding="utf-8")
|
||||
to_json(G, communities, str(out / "graph.json"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user