769 Commits

Author SHA1 Message Date
Safi 9e0b8766f4 Release 0.8.41
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.8.41
2026-06-17 19:09:43 +01:00
Safi c9f2ef5e48 Document this session's fixes in changelog and add JSON-truncation troubleshooting
Add changelog entries for the Swift cross-file (#1356), update prune (#1361),
obsidian canvas (#1324), and edge source_file backfill (#1279) fixes that
shipped without changelog notes, and a README troubleshooting entry for the
LLM JSON-truncation warnings and how to reduce them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:43:08 +01:00
Safi 5b0c154828 Honour configured output-token cap for OpenAI-compatible backends (#1365)
ollama/openai/deepseek/kimi set max_tokens in their backend config, but the
openai-compat dispatch read only max_completion_tokens (which only gemini
defines), so their output silently capped at the 8192 fallback and truncated
deep-mode JSON. Read either key and give the openai config an explicit cap;
GRAPHIFY_MAX_OUTPUT_TOKENS still overrides.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:35:58 +01:00
Safi e9f8dde7af Stop fuzzy dedup over-merging numbered siblings, cross-file boilerplate, and prefix-divergent labels (#1284, #1243)
Three pass-2 guards (mirrored in the --dedup-llm pair collection): block merges
when labels' embedded numbers differ as zero-padding-insensitive multisets;
block cross-file merges of file-anchored rationale/document nodes (same-file
still merges); and score cross-file long labels on plain Jaro instead of
Jaro-Winkler so the prefix bonus can't fabricate merges of shared-prefix but
token-divergent entities (jest-native vs react-native), while genuine cross-file
duplicates still clear Jaro and same-file near-duplicates keep Jaro-Winkler.

Co-Authored-By: van4oza <van4oza@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:21:19 +01:00
Safi 8437ef465e Backfill edge source_file from endpoint nodes (#1279)
Semantic/LLM edges occasionally omit source_file, which build only normalized
when already present, so the field reached graph.json empty and downstream
validation flagged it. Backfill from the source (then target) node in
build_from_json and in the --no-cluster raw-write path, which bypasses it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:49:31 +01:00
Safi 9c8bd4d47c Populate Obsidian canvas when no community data is present (#1324)
to_canvas built cards solely by iterating communities, so a graph with no
community data (--no-cluster builds, or a missing analysis sidecar) wrote the
empty 32-byte {"nodes":[],"edges":[]} shell while notes rendered fine. Fall back
to one synthetic community covering every node so the canvas reflects the graph.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:49:31 +01:00
Safi 2c662c7917 Pass root to build_merge in the update runbook so stale nodes get pruned (#1361)
The /graphify --update runbook called build_merge with absolute prune_sources
but no root=, so _norm_source_file never relativized them to match the graph's
relative source_file values. Nothing was pruned and changed/deleted files left
ghost nodes that compounded on every incremental update. Fix the shared skillgen
fragment to pass root='INPUT_PATH' and re-render all platform artifacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:30:02 +01:00
Safi 2e01f37c81 Resolve cross-file Swift class relationships from member calls and constructors (#1356)
Capture property/field initializer constructor calls, build a per-file Swift
type table from property/parameter declarations, and add a member-call
resolution pass that types the receiver and emits an edge only when the type
name resolves to exactly one definition. Additive and INFERRED-only; the
is_member_call drop and the #543/#1219 god-node guards stay intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:08:59 +01:00
mistic96 d8fa70e17b Harden HTML output against U+2028 XSS + two crash-on-adversarial-input fixes (#1357)
Harden HTML export against U+2028/U+2029 script-breakout XSS + two crash-on-adversarial-input fixes (non-dict LLM JSON, _extract_parallel IndexError). Validated: full suite 2107 passed, HTML export smoke clean. Thanks @mistic96.
2026-06-17 10:46:19 +01:00
RelywOo fd463deb03 fix(build_merge): replace re-extracted files instead of accumulating stale edges (#1344)
build_merge: prune a re-extracted file's stale nodes/edges before merge instead of accumulating (fixes #1283, #1285). Validated: full suite 2107 passed. Thanks @RelywOo.
2026-06-17 10:46:15 +01:00
geektan123 f117aaccc6 feat: PowerShell .psd1 manifest parsing & Import-Module / dot-source edge emission (#1331) (#1341)
Index PowerShell .psd1 manifests + emit Import-Module/dot-source edges (closes #1331). Builds on the shipped .psm1 support. Validated: full suite 2107 passed, 18 new tests. Thanks @geektan123.
2026-06-17 10:46:12 +01:00
Pavel Kudinov a16b3e1b45 fix incremental no-cluster graph updates (#1350)
Harden incremental no-cluster updates: fixes empty-write graph wipeout on no-op update --no-cluster (#1347) and git-hook subdir path resolution (#1348). Complementary to #1317. Validated: full suite 2107 passed, no-op re-run no longer wipes graph. Thanks @pkudinov.
2026-06-17 10:46:08 +01:00
balloon72 9a7dbfbb84 fix js workspace import resolution (#1352)
Fixes #1334: detect npm/yarn package.json workspaces (array + yarn object form), pnpm precedence preserved. Reviewed: full suite 2087 passed, no regressions. Thanks @balloon72.
2026-06-17 10:29:47 +01:00
balloon72 d885833112 fix node label lookup normalization (#1353)
Fixes #1338 (Unicode NFD/NFC): serve._find_node now matches tokenized labels; affected.resolve_seed NFC-normalizes + casefolds. Reviewed: full suite 2087 passed, CLI smoke clean, no regressions. Thanks @balloon72.
2026-06-17 10:29:43 +01:00
Safi be3dcfca08 Unify query skill: ship expansion + inline fallback to every platform
The query skill was split across two fragments so no platform got both
capabilities: Claude had the vocab/IDF query-expansion step but no fallback if
the CLI was unavailable; every other platform had the inline NetworkX fallback
but the weaker raw-question matcher. Merge into one unified query reference +
stub (Step 0 expansion -> CLI traversal -> inline NetworkX fallback, plus
path/explain inline) shipped to all hosts. Remove the query_variant enum, its
toml field, and the _CLI_ONLY_QUERY_HEADINGS coverage-audit exemption. Re-render
all skill artifacts and re-bless expected/. skillgen check/audit-coverage/
monolith-roundtrip/schema-singleton all pass. Refs #1325.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 03:33:23 +01:00
Safi 2100b3d05b Resolve cross-file Java type references by import package
Same-named types in different packages left implements/inherits edges stuck on
bare shadow stubs, isolating the real interface (_rewire_unique_stub_nodes only
fixes the globally-unique case). New _resolve_java_type_references pass uses each
referencing file's import statements (+ package decl) to build an FQN->def index,
re-points dangling implements/inherits/imports edges to the exact definition, and
drops the orphaned stub. External/stdlib imports stay unresolved (correct). Runs
after id-disambiguation so target ids are final. Java-scoped; other _extract_generic
languages share the same bare-name fallback and remain a follow-up.

Adds tests/test_java_type_resolution.py (simple, ambiguous-by-import, build-survival).
Refs #1318.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 03:16:08 +01:00
Safi 4fbb33301c Collapse Swift module imports to one shared node
Adopts the approach from #1330 (thanks @duncan-daydream) on top of the v0.8.40
Swift import fix: _import_swift returns (id,label) module pairs, the extractor
materializes a type=module anchor node per import, and _disambiguate_colliding_node_ids
exempts type=module nodes so the same module imported from N files collapses to
one shared node (enables reverse traversal "what imports CoreKit"). The --no-cluster
writer now dedupes nodes by id and edges to match the clustered build_from_json path.

Replaces the interim _import_label/synthesize_import_module_nodes mechanism.
Adds tests/test_swift_import_resolution.py (cross-file collapse, build survival)
and dedupe_nodes coverage. Refs #1327, #1330.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 03:06:43 +01:00
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