You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feat: graphify label --missing-only relabels only communities that are unnamed or still hold a Community N placeholder, preserving existing non-placeholder labels from .graphify_labels.json (#1481, thanks @jiangyq9; supersedes #1421 by @matiasduartee, who proposed the same flag). Lets a large graph be relabeled incrementally without re-naming (and paying for) communities that already have good names.
Feat: index Metal (.metal) shader files — Metal Shading Language is C++14, so .metal is classified as code and routed through the existing C++ extractor, mirroring the CUDA .cu/.cuh reuse (#1480, thanks @jiangyq9; supersedes #1450 by @GoodOlClint). Also adds .cu/.cuh/.metal to the cross-language edge-filter family map (they were missing), so phantom cross-language calls edges between these and C++ are correctly suppressed.
Fix: pass stream: False explicitly on OpenAI-compatible chat-completion calls (#1223, thanks @jiangyq9). Some gateways default to SSE streaming when stream is omitted, but graphify always reads the result as a single response, so the call failed against those gateways. Applied to both the extraction dispatch path and the --dedup-llm tiebreaker path.
Fix: emit references edges for Java field types (#1485) and for type-level annotations on Java classes/interfaces/records (#1487, both thanks @oleksii-tumanov). Field types (including the generic_arg element of List<Handler>) and class annotations (@Service, @Entity) were missing from the graph even though parameter/return types and method annotations were already captured; primitives are still skipped.
Fix: the Objective-C extractor was silently dropping most code-level relationships (#1475, thanks @JabberYQ for the detailed report). Five fixes: (1) ObjC .h headers were parsed by the C extractor (1 node, 0 edges, losing every @interface/@protocol/@property/method) — a .h is now routed to the ObjC extractor when it contains an ObjC-only directive (@interface/@protocol/@implementation/@import), which never hijacks a real C/C++ header; (2) [receiver selector] calls produced no calls edges at all because the method-body pass looked for selector/keyword_argument_list nodes, but the grammar tags selector parts with the field name method (type identifier) — the selector is now read from the method fields, skipping the receiver, which also makes compound sends like [self a:x b:y] resolve; (3) generic property types (NSArray<Product *> *) were invisible because the type was wrapped in a generic_specifier — the element and container types are now both referenced; (4) class methods (+foo) were mislabeled -foo; (5) @import Foundation; now produces an imports edge. Property/dot-syntax accesses and @selector(...) target-action edges remain follow-ups.
Feat: link WPF/XAML views to their ViewModels and extract richer binding references (#1473, thanks @MikeKatsoulakis). Builds on the initial XAML support (#1460). Resolves a view to its ViewModel from an explicit <Window.DataContext><vm:MainViewModel/>, a design-time d:DataContext="{d:DesignInstance Type=…}", the View→ViewModel naming convention, or Prism ViewModelLocator.AutoWireViewModel="True" — always against an actually-extracted C# class, so a name with no matching class (or an ambiguous one) emits no edge (explicit DataContext is EXTRACTED, conventions are INFERRED). Also extracts binding paths ({Binding User.Name}, Path=Order.Total), commands (Command="{Binding SaveCommand}"), converters, and CommunityToolkit [ObservableProperty]/[RelayCommand] generated members. The event-handler resolution stays gated on the .NET handler signature (no spurious event edges), and ViewModel discovery is bounded to the extraction root.
Fix: .vue Single File Components now extract their <script> with the right grammar (#1468, thanks @papinto). .vue was dispatched to extract_js, which selects a tree-sitter grammar by suffix; .vue is neither .ts nor .tsx, so the whole SFC — <template> markup, <script>, and <style> — was parsed as JavaScript, producing a top-level ERROR node and recovering no imports, symbols, or type references. A dedicated extract_vue now masks everything outside <script> (replacing it with spaces so line numbers stay accurate) and parses just the script with the grammar named by lang (ts default, tsx/js/jsx honored). The open-tag scan tolerates > inside quoted attributes, so Vue 3.3+ generic components (generic="T extends Record<string, unknown>") parse correctly.
Fix: graphify reflect --if-stale now also checks the .graphify_analysis.json and .graphify_labels.json sidecars (and any custom --analysis/--labels paths) when deciding whether LESSONS.md is up to date (#1470, thanks @oleksii-tumanov). It previously only stat'd the memory docs and graph.json, so lessons could stay stale after community analysis or labels changed without the graph changing. A missing sidecar is treated as not-an-input, so no-cluster builds are unaffected.
Fix: the Read|Glob PreToolUse hook (the "run graphify first" nudge installed for Claude Code and CodeBuddy) now matches the file's real trailing extension instead of substring-scanning the path (#1463, thanks @marketechniks). The old check asked any(ext in path), which had two opposite failures: .json files (package.json, tsconfig.json) spuriously fired because .js is a substring of .json, and .astro/.vue/.svelte never fired because they weren't in the set — so on Astro/Vue/Svelte projects, where those are the primary source type, reads and globs never surfaced the graph. The hook now compares the segment after the last / then after the last . against the extension set (with .astro/.vue/.svelte added), so package.json stays silent, data.geojson stays silent, **/*.astro fires, and an extension sitting on a directory component (my.ts/file) correctly doesn't. The graphify-out/ suppression and fail-open behavior are unchanged.
Fix: make it unambiguous in the skill that graphify needs no API key, so terminal-style hosts stop looping on a missing one (#1461). Hermes (and the other AGENTS.md hosts: Codex, Aider, OpenClaw, Droid, Trae, …) run the graphify CLI directly and don't dispatch subagents, but the Step 3 extraction guidance framed the no-key path only as "fall through to subagent dispatch" — so on /graphify . those agents would spin for minutes insisting they needed an API key before eventually proceeding. Step 3 now opens with an explicit, hoisted "graphify needs no API key — never ask the user for one, never block on one" statement (code is AST-only; a code-only corpus skips semantic extraction entirely), and the fallback now spells out a non-subagent path for terminal hosts instead of assuming subagent dispatch. Applied across every generated skill body, including the aider/devin monoliths, with a regression test that pins the wording in place.
Feat: extract WPF/XAML structure from .xaml files (#1460, thanks @MikeKatsoulakis). No new parser dependency (stdlib XML, with the same DOCTYPE/ENTITY and size guards as the .csproj extractor). Captures the root element, named controls (x:Name/Name) and their control types, {Binding ...} references, and x:Class, and bridges the view to its .xaml.cs code-behind by resolving event-handler attributes to the matching methods on the partial class. Event resolution is gated on the .NET handler signature (object sender, …EventArgs e) and skips free-form attributes (Content, Text, Tag, …), so a property value that merely matches a method name (e.g. Content="Save" next to a business method Save()) can't fabricate a spurious event edge.
Fix: to_canvas (Obsidian Canvas export) now lays out each community's node cards in the same ceil(sqrt(n))-column grid the group box is sized for. The box width assumed a roughly-square sqrt(n)-column layout, but the placement loop hardcoded 3 columns, so any community larger than ~9 members rendered as a cramped 3-wide strip in an over-wide, mostly-empty box. The column count is now computed once per community and reused for the box width, box height, and card placement, so the cards fill the box. Cosmetic, no data change (#1452, thanks @TPAteeq).
Fix: to_obsidian / to_canvas / to_wiki no longer silently overwrite notes whose labels differ only by case (e.g. a class References and a prose heading references). The filename dedup was keyed on the exact-case name, so two such labels counted as non-colliding and the second write clobbered the first on case-insensitive filesystems (macOS/APFS, Windows/NTFS) — no suffix, no warning. Dedup now folds case (keyed on the lowercased name) while still emitting the original-case filename, so any pair that would collide on disk gets a numeric suffix. The obsidian/canvas dedup is shared in one helper so they can't drift, wiki's slug dedup gets the matching fix, the _COMMUNITY_*.md overview notes (which had no dedup) are covered, and a generated base_1 is itself re-checked so it can't overwrite a node literally labelled base_1 (#1453, thanks @TPAteeq).
Feat: the kimi, gemini, and deepseek semantic-extraction backends now honor KIMI_BASE_URL, GEMINI_BASE_URL, and DEEPSEEK_BASE_URL to point at any OpenAI-compatible endpoint (a proxy, gateway, or self-hosted relay), matching the existing OLLAMA_BASE_URL / OPENAI_BASE_URL overrides. Each falls back to its hardcoded official default when the variable is unset, so behavior is unchanged for everyone who doesn't set it (#1458, thanks @jc2shile).
Fix: to_wiki (Wikipedia-style wiki export) now emits portable relative markdown links instead of Obsidian [[wikilinks]], so navigation works in every renderer — VS Code preview, GitHub, GitLab, a plain browser — not just Obsidian. Two defects: (1) [[Title]] resolves by note title only inside Obsidian; everywhere else [[Domain Data Models]] points at a literal Domain Data Models.md, but the article file is Domain_Data_Models.md (the slug substitutes spaces and reserved characters), so nearly every community/god-node navigation link opened an empty page. (2) God-node articles linked every neighbor ([[AwsHelper.py]], [[.read_object_key()]]), but only communities and god nodes get article files, so those node-level links were dead even inside Obsidian. Links are now standard [display](slug.md) with the target URL-encoded, so spaces, &, parentheses, and # survive intact in CommonMark renderers and Obsidian alike; any link whose target has no article is downgraded to plain text instead of left dangling. Each article's slug is computed up front (a label -> slug resolver built before any body is rendered) so a link to a community or god-node article points at the real on-disk filename, including the case-fold collision suffix (parser_2.md). Cosmetic, no graph/data change (#1444, thanks @restagner).