Commit Graph

748 Commits

Author SHA1 Message Date
Safi fd470faeee docs: add --graph flag example to graphify-mcp usage (#1304) 2026-06-13 19:44:36 +01:00
Safi a4f3e862b2 changelog: document community name fix and --graph alias (#1304, #1305) 2026-06-13 19:36:12 +01:00
Safi 85de47e121 fix: community names blank in query/MCP after cluster-only; --graph for graphify-mcp
export.py: to_json now accepts community_labels and writes community_name onto
each node. Previously cluster-only wrote labels only to GRAPH_REPORT.md,
graph.html, and .graphify_labels.json — graph.json stored only the numeric cid,
so query/MCP showed blank or numeric community values (#1305).

__main__.py: pass community_labels=labels to to_json in cluster-only path.
explain command now prefers community_name over raw numeric community field.

serve.py: query and get_node read paths prefer community_name over community,
with fallback so old graphs without the field still work. Adds --graph flag as
an alias for the positional argument in graphify-mcp/_main(), fixing
"unrecognized arguments: --graph" for users following the documented pattern
shared by every other graphify subcommand (#1304).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 19:34:18 +01:00
Safi b61c985c12 changelog: document #1209 security CI and #1166 node-summaries RFC 2026-06-13 16:03:58 +01:00
Safi 591cc934a7 Merge pull request #1166 from leonaburime-ucla/docs/node-summaries-rfc
docs: add RFC for file-level node summaries
2026-06-13 15:56:42 +01:00
Safi 9bed8318c6 Merge pull request #1209 from nucleusjay/ci-run-security-scanners
Wire bandit and pip-audit into CI
2026-06-13 15:56:39 +01:00
Safi 10655b92eb changelog: document four bug fixes (#1257, #1288, #1298, #1299) 2026-06-13 15:16:17 +01:00
Safi b83086297f fix: four production bugs — Windows crashes, ghost-merge collision, version probe
extract.py: clamp ProcessPoolExecutor max_workers to 61 on Windows (issue #1298).
Python's ProcessPoolExecutor hard-caps at 61 on Windows via WaitForMultipleObjects;
>61-core machines crashed on AST extraction. Clamp applied after all input paths
(auto-compute, GRAPHIFY_MAX_WORKERS, --max-workers) to cover all three.

build.py: skip ghost-merge when two AST nodes share (basename, label) key (issue #1257).
When same-named symbols appear in same-named files across directories (e.g. two
render() in two index.ts), last-writer-wins produced an arbitrary canonical node
and mis-pointed all edges. Now tracked in _loc_collisions; ambiguous keys are
skipped in Pass 2, leaving the ghost intact rather than merging into the wrong node.

__main__.py: ignore OSError on unreadable .graphify_version probes (issue #1299).
On restricted-permission installs or network mounts, .exists()/.read_text() raised
PermissionError and crashed every graphify query/explain/path call at startup.
All three FS probes now wrapped in try/except OSError: return.

prs.py: resolve claude.cmd on Windows in prs.py claude-cli backend (issue #1288).
The _call_llm and _call_claude_cli paths were already fixed; prs.py had the same
bare ["claude", ...] call that fails on Windows npm installs with WinError 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 15:13:23 +01:00
Safi 813db19252 Merge pull request #1295 from sirphilliptubell/perf/fix5
perf: parallelize save_manifest file hashing with ThreadPoolExecutor
2026-06-13 11:28:43 +01:00
Safi dbbf0a45a1 Merge pull request #1294 from sirphilliptubell/perf/fix4
perf: convert _walk_js_tree from recursive generator to iterative
2026-06-13 11:28:40 +01:00
Sir Phillip Tubell 0f6d46f822 perf: parallelize save_manifest file hashing with ThreadPoolExecutor
stat+MD5 across all files now fans out over a thread pool instead of running sequentially — I/O-bound work releases the GIL so this scales with available disk concurrency.
2026-06-12 16:07:51 -04:00
Safi c4689a2f47 bump version to 0.8.39 v0.8.39 2026-06-12 20:36:47 +01:00
Sir Phillip Tubell a7c69808ac perf: convert _walk_js_tree from recursive generator to iterative
Eliminates O(depth) generator-frame chain overhead. Each leaf's value previously propagated through 26+ yield-from frames; now a single stack loop handles the full traversal.
2026-06-12 15:19:44 -04:00
Safi 3929eca450 changelog: add unreleased entries for #1289, #1207, #1208, #1176 2026-06-12 20:18:17 +01:00
Safi 70a1ad7278 Merge pull request #1176 from galshubeli/falkordb-backend
feat: add FalkorDB export backend (#1175)
2026-06-12 20:15:30 +01:00
Safi 70380b8ea0 Merge pull request #1208 from nucleusjay/pin-tree-sitter-deps
Pin tree-sitter dependency version ranges
2026-06-12 20:15:27 +01:00
Safi 3e8cd7da6d Merge pull request #1207 from nucleusjay/fix-merge-chunks-and-manifest-bugs
Fix two latent bugs: merge-chunks output and manifest data loss
2026-06-12 20:15:23 +01:00
Safi 418fab8e23 Merge pull request #1289 from sirphilliptubell/perf/fix1
perf: fix O(n^2) -> O(n) LSH neighbor lookup in dedup
2026-06-12 20:15:20 +01:00
Safi 6c2f273742 changelog: add unreleased entries for #1280, #1276, #1282, #1281 2026-06-12 19:58:49 +01:00
Safi 5a21685bf1 Merge pull request #1281 from BemoBit/docs/fa-readme
docs: add Persian (فارسی) translation and language selector link
2026-06-12 19:54:47 +01:00
Safi fb1908cc55 Merge pull request #1282 from balloon72/codex/community-label-model
feat: add --model to community labeling commands
2026-06-12 19:54:44 +01:00
Safi 90decbc4ed Merge pull request #1276 from papinto/fix/graphifyignore-negation-pruning
fix: a single negation (!) in .graphifyignore no longer disables all directory pruning
2026-06-12 19:54:41 +01:00
Safi 0ff84d8bf3 Merge pull request #1280 from s22hyun/fix/affected-edges-key
fix(affected): handle "edges"-keyed graph.json in load_graph (KeyError: 'links')
2026-06-12 19:54:38 +01:00
Sir Phillip Tubell c4d6b412ca perf: fix O(n^2) -> O(n) LSH neighbor lookup in dedup
Replaced O(n) linear scan `next((n for n in candidates if n["id"] == neighbor_id))` with O(1) dict lookup via pre-built `candidates_by_id`. Also pre-caches `_norm()` results in `norm_cache` to avoid recomputing per inner iteration.

For a 36k-file codebase (~100k high-entropy candidates) this reduces the pass-2 loop from O(n^2*B) (~30–100B iterations) to O(n*B), eliminating the multi-minute CPU hang after AST extraction completes.
2026-06-12 10:31:01 -04:00
hanmo1 b304331d24 feat: add model override for community labeling 2026-06-12 17:57:19 +08:00
Behnam Moradi 0e74c0401e docs: add Persian (فارسی) translation and language selector link
Adds complete Persian translation (README.fa-IR.md) with RTL formatting and updates main README language selector to include Persian between Arabic and Italian.
2026-06-12 11:15:32 +03:30
s22hyun 2ab2302112 fix(affected): handle "edges"-keyed graph.json in load_graph (KeyError: 'links') 2026-06-12 15:33:33 +09:00
Safi 1bb30fcc56 bump version to 0.8.38 v0.8.38 2026-06-11 23:46:54 +01:00
Safi b739cf2fda changelog: document all v8 unreleased fixes and features
Covers 13 merged PRs: LLM calls-edge direction fix, JS default
imports/exports, tsconfig baseUrl paths, ghost-merge collision skip,
resolve_seed callable labels, AST cache versioning, global-graph edge
rewiring, dedup pass-2 winner, cache --out anchor, single-walk collect,
frontmatter delimiters, claude-cli Windows headless + JSON array envelope,
Cargo extractor, SystemVerilog/Dart improvements, README grammar count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 23:42:11 +01:00
Safi 3a47091021 docs: update tree-sitter grammar count from 28 to 36
Reflects languages now supported: Python, TypeScript/TSX, JavaScript/JSX,
Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP, Swift, Lua, Zig,
PowerShell, Elixir, Objective-C, Julia, Vue, Svelte, Astro, Groovy, Dart,
Verilog, SystemVerilog, SQL, Fortran, Pascal/Delphi, Shell/Bash, JSON,
DreamMaker, HCL/Terraform, R, and .NET XML project files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 23:38:46 +01:00
Jamie Evans 6dc23db90f fix: emit symbol edges for default imports/exports
JS/TS symbol resolution only handled named imports. A default-exported
symbol (`export default class Foo`) imported as `import Foo from './foo'`
produced only a file→file `imports_from` edge; the class node received no
incoming symbol edge. On codebases that default-export most classes
(NestJS services/helpers/models, etc.) those symbols looked like isolated
leaf nodes, and `graphify affected "<Class>"` / `explain` reported no
callers.

Record default imports with imported_name="default", register a "default"
export for `export default <class|function|identifier>`, and let the
existing exported-origin resolver wire the `imports` edge — which also
resolves calls made through the local binding, even when it is renamed
(`import Bar from './foo'; new Bar()`). `export { X as default }` was
already handled via the export-clause path; anonymous defaults
(`export default class {}`) have no resolvable symbol and stay file-level.

Adds regression tests for default-export class/function/identifier import
resolution and renamed-binding call resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:24:59 +01:00
Safi d276a5aa57 Merge pull request #1271 from giovanecesar/feat/cargo-introspect
feat(extract): add opt-in --cargo crate dependency extractor
2026-06-11 23:22:50 +01:00
Safi 60d4b4373f Merge pull request #1269 from jevans-agent/fix/tsconfig-paths-baseurl
fix: resolve tsconfig path aliases relative to baseUrl
2026-06-11 23:22:45 +01:00
Safi e16c1f37bf Merge pull request #1266 from PowPickles/fix/claude-cli-windows-spawn
fix: claude-cli backend works headlessly on Windows npm installs
2026-06-11 23:22:41 +01:00
Safi b87329496f Merge pull request #1265 from PowPickles/fix/resolve-seed-callable-decoration
fix: resolve_seed matches bare names against ()-decorated callable labels
2026-06-11 23:22:38 +01:00
Safi 0be4e81047 Merge pull request #1246 from VLDCNDN/fix/extract-out-cache-leak
fix: anchor extraction cache at --out root so external output leaves the scanned project clean
2026-06-11 23:22:35 +01:00
Safi b7b59ca9ea Merge pull request #1244 from PCeltide/fix/claude-cli-json-array-envelope
fix(claude-cli): handle JSON-array envelope from Claude Code CLI ≥ 2.1
2026-06-11 23:22:30 +01:00
Safi 5b60624acd Merge pull request #1267 from TheFedaikin/v8
uv.lock sync, SystemVerilog class-level extraction + Dart mixin fix
2026-06-11 23:22:27 +01:00
Safi 3ea6def727 Merge pull request #1262 from teemow/fix/collect-files-single-walk
fix(extract): collect files in a single pruned walk instead of one rglob per extension (#1261)
2026-06-11 23:22:23 +01:00
Safi b34902b8d7 Merge pull request #1260 from teemow/fix/frontmatter-delimiters
fix(cache): require whole --- lines as frontmatter delimiters (#1259)
2026-06-11 23:22:20 +01:00
Safi e364f72fd8 Merge pull request #1253 from teemow/fix/ast-cache-version
fix(cache): namespace AST cache by graphify version (#1252)
2026-06-11 23:22:15 +01:00
Safi 556cab3c2c Merge pull request #1251 from teemow/fix/global-graph-external-edges
fix(global-graph): rewire edges to deduplicated external nodes (#1250)
2026-06-11 23:22:11 +01:00
Safi 2117983b87 Merge pull request #1248 from teemow/fix/dedup-pass2-winner-union
fix(dedup): pick pass-2 winner from the verified pair only (#1247)
2026-06-11 23:21:39 +01:00
Paulo Pinto e8ab8f4172 fix: negation pattern no longer disables all directory pruning
A single `!` rule in .graphifyignore set a blanket `has_negation` flag that
disabled directory-level pruning for EVERY ignored directory during the
os.walk in detect(). One unrelated `!docs/**` therefore made the walk descend
bin/, obj/, wwwroot/, generated/, … on large repos — a pathological slowdown.
Output stayed correct (the per-file `_is_ignored` filter still excluded those
files), but the walk visited the entire tree.

The bypass was unnecessary: `_is_ignored` already honours negations correctly —
last-match-wins lets `!dir/` un-ignore a directory (so it is not pruned), and
the gitignore parent-exclusion rule means a `!` cannot rescue a file beneath an
excluded directory, so descending an ignored dir to find a re-included file is
never needed. Prune purely on `_is_noise_dir` + `_is_ignored`.

Adds a regression test that tracks os.walk and asserts the ignored dir is never
descended while the negation still re-includes its target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 14:50:44 -07:00
Giovane Cesar da Silva b56a415388 feat(extract): add opt-in --cargo crate dependency extractor
Closes #1264

Also fixes a narrow watch-mode path-filtering bug found while running the required local
full-suite gate for this PR. Hidden directories inside the watched corpus are still ignored;
hidden ancestors outside the watched root no longer suppress valid file events.
2026-06-11 15:08:36 -06:00
Jamie Evans ec04152a90 fix: resolve tsconfig path aliases relative to baseUrl
_read_tsconfig_aliases joined alias targets onto the tsconfig's own
directory and ignored compilerOptions.baseUrl. In the common monorepo /
NestJS layout (baseUrl "./src" with "@services/*": ["services/*"]), the
alias resolved to <dir>/services instead of <dir>/src/services, so every
aliased import failed to resolve and the import edge was silently dropped
— leaving cross-file caller graphs nearly empty on alias-heavy TS repos.

Resolve `paths` relative to `baseUrl` (TypeScript's actual semantics),
defaulting to "." so configs without baseUrl keep their current behavior.
Add a regression test covering a subdirectory baseUrl; the existing alias
test only exercised baseUrl ".", which is why this slipped through.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 14:20:09 -04:00
Danil Tarasov b525549a24 feat(extract): SystemVerilog class-level extraction; Dart with-clause mixin fix 2026-06-11 19:52:56 +03:00
Skyler Southern 96585badd0 fix: claude-cli backend works headlessly on Windows npm installs
Two Windows fixes for the claude-cli backend:

1. _call_llm (the label/community-naming path) spawned a bare ["claude", ...],
   which CreateProcess cannot resolve to the npm claude.cmd shim (PATHEXT does
   not apply) — every labeling batch failed with WinError 2. Mirror the
   extraction path's resolution: prefer shutil.which("claude.cmd") and pass
   the resolved path. Regression test included.

2. Both claude -p spawn sites now pass CREATE_NO_WINDOW on Windows. Without
   it, each per-batch claude.cmd spawn allocates a console — with Windows
   Terminal as the default terminal, a labeling run pops one visible window
   per batch on the user's desktop for the duration of the model call.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 09:58:39 -04:00
Skyler Southern 58efcebd83 fix: resolve_seed matches bare names against ()-decorated callable labels
Callable nodes are labeled with a trailing "()" (e.g. classifyProperty()),
so a bare-name query like "classifyProperty" falls through the exact-label
pass and then ties with any prefix sibling (classifyPropertySafe()) in the
contains pass, returning "No unique node match" even though exactly one
callable with that name exists.

Add a bare-name pass between exact-label and exact-source matching that
compares query and label with the trailing "()" stripped from each. Bare
queries now resolve decorated labels and vice versa; genuine duplicates
still return None.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 09:14:28 -04:00
Safi cce2673021 fix: LLM calls-edge direction reversal and ghost-node merge
llm.py: add explicit edge direction rule to extraction system prompt —
source = actor (caller/importer/subclass), target = acted-upon (callee/
imported/base). LLM was systematically emitting callee->caller for calls
edges because the schema never stated direction semantics.

build.py: extend ghost-node merge to catch LLM nodes that populate
source_location (bypassing the old None check). Now uses _origin=="ast"
as the canonical signal — AST nodes always win; any non-AST node sharing
(basename, label) with an AST node is collapsed into the AST canonical.
Fixes LLM bare-stem IDs (bpe_get_pairs) surviving alongside AST
parent-qualified IDs (mingpt_bpe_get_pairs) and carrying reversed edges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 12:03:59 +01:00