mirror of
https://github.com/safishamsi/graphify.git
synced 2026-09-24 14:35:46 +00:00
Fix 6 bugs: hook exit code, token budget, file node detection, duplicate function, atomic cache writes, deleted file tracking
This commit is contained in:
+8
-4
@@ -16,12 +16,16 @@ def _is_file_node(G: nx.Graph, node_id: str) -> bool:
|
||||
These are synthetic nodes created by the AST extractor and should be excluded
|
||||
from god nodes, surprising connections, and knowledge gap reporting.
|
||||
"""
|
||||
label = G.nodes[node_id].get("label", "")
|
||||
attrs = G.nodes[node_id]
|
||||
label = attrs.get("label", "")
|
||||
if not label:
|
||||
return False
|
||||
# File-level hub: label is a filename with a code extension
|
||||
if label.split(".")[-1] in ("py", "ts", "js", "go", "rs", "java", "rb", "cpp", "c", "h"):
|
||||
return True
|
||||
# File-level hub: label matches the actual source filename (not just any label ending in .py)
|
||||
source_file = attrs.get("source_file", "")
|
||||
if source_file:
|
||||
from pathlib import Path as _Path
|
||||
if label == _Path(source_file).name:
|
||||
return True
|
||||
# Method stub: AST extractor labels methods as '.method_name()'
|
||||
if label.startswith(".") and label.endswith("()"):
|
||||
return True
|
||||
|
||||
+8
-1
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -46,7 +47,13 @@ def save_cached(path: Path, result: dict, root: Path = Path(".")) -> None:
|
||||
"""
|
||||
h = file_hash(path)
|
||||
entry = cache_dir(root) / f"{h}.json"
|
||||
entry.write_text(json.dumps(result))
|
||||
tmp = entry.with_suffix(".tmp")
|
||||
try:
|
||||
tmp.write_text(json.dumps(result))
|
||||
os.replace(tmp, entry)
|
||||
except Exception:
|
||||
tmp.unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
|
||||
def cached_files(root: Path = Path(".")) -> set[str]:
|
||||
|
||||
@@ -266,9 +266,14 @@ def detect_incremental(root: Path, manifest_path: str = _MANIFEST_PATH) -> dict:
|
||||
else:
|
||||
unchanged_files[ftype].append(f)
|
||||
|
||||
# Files in manifest that no longer exist - their cached nodes are now ghost nodes
|
||||
current_files = {f for flist in full["files"].values() for f in flist}
|
||||
deleted_files = [f for f in manifest if f not in current_files]
|
||||
|
||||
new_total = sum(len(v) for v in new_files.values())
|
||||
full["incremental"] = True
|
||||
full["new_files"] = new_files
|
||||
full["unchanged_files"] = unchanged_files
|
||||
full["new_total"] = new_total
|
||||
full["deleted_files"] = deleted_files
|
||||
return full
|
||||
|
||||
+1
-5
@@ -8,6 +8,7 @@ from pathlib import Path
|
||||
import networkx as nx
|
||||
from networkx.readwrite import json_graph
|
||||
from graphify.security import sanitize_label
|
||||
from graphify.analyze import _node_community_map
|
||||
|
||||
COMMUNITY_COLORS = [
|
||||
"#4E79A7", "#F28E2B", "#E15759", "#76B7B2", "#59A14F",
|
||||
@@ -17,11 +18,6 @@ COMMUNITY_COLORS = [
|
||||
MAX_NODES_FOR_VIZ = 5_000
|
||||
|
||||
|
||||
def _node_community_map(communities: dict[int, list[str]]) -> dict[str, int]:
|
||||
"""Invert communities dict: node_id -> community_id."""
|
||||
return {n: cid for cid, nodes in communities.items() for n in nodes}
|
||||
|
||||
|
||||
def _html_styles() -> str:
|
||||
return """<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
+3
-1
@@ -40,7 +40,7 @@ try:
|
||||
_rebuild_code(Path('.'))
|
||||
except Exception as exc:
|
||||
print(f'[graphify hook] Rebuild failed: {exc}')
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
"
|
||||
"""
|
||||
|
||||
@@ -69,10 +69,12 @@ echo "[graphify] Branch switched - rebuilding knowledge graph (code files)..."
|
||||
python3 -c "
|
||||
from graphify.watch import _rebuild_code
|
||||
from pathlib import Path
|
||||
import sys
|
||||
try:
|
||||
_rebuild_code(Path('.'))
|
||||
except Exception as exc:
|
||||
print(f'[graphify] Rebuild failed: {exc}')
|
||||
sys.exit(1)
|
||||
"
|
||||
"""
|
||||
|
||||
|
||||
+2
-2
@@ -75,8 +75,8 @@ def _dfs(G: nx.Graph, start_nodes: list[str], depth: int) -> tuple[set[str], lis
|
||||
|
||||
|
||||
def _subgraph_to_text(G: nx.Graph, nodes: set[str], edges: list[tuple], token_budget: int = 2000) -> str:
|
||||
"""Render subgraph as text, cutting at token_budget (approx 4 chars/token)."""
|
||||
char_budget = token_budget * 4
|
||||
"""Render subgraph as text, cutting at token_budget (approx 3 chars/token)."""
|
||||
char_budget = token_budget * 3
|
||||
lines = []
|
||||
for nid in sorted(nodes, key=lambda n: G.degree(n), reverse=True):
|
||||
d = G.nodes[nid]
|
||||
|
||||
Reference in New Issue
Block a user