752 Commits

Author SHA1 Message Date
Safi fd152add64 Release 0.8.40
Bump version to 0.8.40; document this release in CHANGELOG (PowerShell .psm1
indexing, Swift import survival, no-cluster edge dedup, custom OpenAI/Anthropic
endpoints, JS/TS assignment-form extraction, community-name + --graph fixes,
four production bug fixes, perf, security CI); add .psm1 to the README
supported-extensions table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.8.40
2026-06-16 02:38:28 +01:00
Safi adb52a1ea0 Index .psm1, anchor Swift import targets, dedupe no-cluster edges
- #1315: add .psm1 to CODE_EXTENSIONS + _DISPATCH so PowerShell modules are indexed
- #1327: synthesize a module node for Swift import targets (new LanguageConfig
  flag synthesize_import_module_nodes) so imports edges survive build.py pruning;
  strengthen the Swift dangling-edge test to also assert edge targets
- #1317: dedupe parallel edges by (source,target,relation) in the --no-cluster
  and incremental update write paths so edge counts are deterministic and
  `update` is idempotent

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 02:28:16 +01:00
Siddarth Chintamani 09da5294e4 feat: extract JS/TS this.X=, exports.X=, prototype, class arrow fields, function expressions (#1323)
Extract JS/TS this.X=, exports.X=, prototype, class arrow fields, and function expressions (closes #1322). Validated locally against v8: full suite 2069 passed.
2026-06-16 02:14:31 +01:00
Timon 61836ce0e8 feat: custom endpoints via OPENAI_BASE_URL/OPENAI_MODEL and ANTHROPIC_BASE_URL/ANTHROPIC_MODEL (#1273)
Custom OPENAI/ANTHROPIC base-url + model env vars for self-hosted and proxy endpoints. CI green (3.10/3.12).
2026-06-16 01:41:15 +01:00
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