- GDScript support (Godot):
.gdfiles are parsed via thegdscripttree-sitter grammar shipped withtree-sitter-language-pack. Extracts inner classes (class Name:), the file-levelclass_nameidentity, functions (includingstatic func),extendsparent class as an IMPORTS_FROM edge, direct calls (call) and method calls (attribute_call). Adds 10 tests andtests/fixtures/sample.gd.
Major feature release — 15 new capabilities, 6 community PRs merged, 6 new MCP tools, 4 new languages, multi-format export, and graph analysis suite.
- Hub node detection (
get_hub_nodes_tool): find the most-connected nodes in the codebase (architectural hotspots) by in+out degree, excluding File nodes. - Bridge node detection (
get_bridge_nodes_tool): find architectural chokepoints via betweenness centrality with sampling approximation for graphs >5000 nodes. - Knowledge gap analysis (
get_knowledge_gaps_tool): identify structural weaknesses — isolated nodes, thin communities (<3 members), untested hotspots, and single-file communities. - Surprise scoring (
get_surprising_connections_tool): composite scoring for unexpected architectural coupling (cross-community, cross-language, peripheral-to-hub, cross-test-boundary). - Suggested questions (
get_suggested_questions_tool): auto-generate prioritized review questions from graph analysis (bridge nodes, untested hubs, surprising connections, thin communities). - BFS/DFS traversal (
traverse_graph_tool): free-form graph exploration from any node with configurable depth (1-6) and token budget. - Edge confidence scoring: three-tier system (EXTRACTED/INFERRED/AMBIGUOUS) with float confidence scores on all edges. Schema migration v9.
- Export formats: GraphML (Gephi/yEd/Cytoscape), Neo4j Cypher statements, Obsidian vault (wikilinks + YAML frontmatter + community pages), SVG static graph. CLI:
visualize --format graphml|cypher|obsidian|svg. - Graph diff: snapshot/compare graph state over time — new/removed nodes, edges, community membership changes.
- Token reduction benchmark: measure naive full-corpus tokens vs graph query tokens with per-question reduction ratios.
- Memory/feedback loop: persist Q&A results as markdown for re-ingestion via
save_result/list_memories/clear_memories. - Oversized community auto-splitting: communities exceeding 25% of graph are recursively split via Leiden algorithm.
- 4 new languages: Zig, PowerShell, Julia, Svelte SFC (23 total).
- Visualization enhancements: node size scaled by degree, community legend with toggle visibility, improved interactivity.
- README translations: Simplified Chinese, Japanese, Korean, Hindi.
- #127 (xtfer): SQLite compound edge indexes for query performance.
- #184 (realkotob): batch
_compute_summaries— fixes build hangs on large repos. - #202 (lngyeen): Swift extension detection, inheritance edges, type kind metadata.
- #249 (gzenz): community detection resolution scaling (21x speedup), expanded framework patterns, framework-aware dead code detection (56 new tests).
- #253 (cwoolum): automatic graph build for new worktrees in Claude Code.
- #267 (jindalarpit): Kiro platform support with 9 tests.
- MCP tool count: 22 → 28.
- Schema version: 8 → 9 (edge confidence columns).
- Community detection uses resolution scaling for large graphs.
- Risk scoring uses weighted flow criticality and graduated test coverage.
- Dead code detection is framework-aware (ORM models, Pydantic, CDK constructs filtered).
- Flow entry points expanded with 30+ framework decorator patterns.
Hotfix for the Windows long-running-MCP-tool hang that v2.2.4 only partially fixed.
- Windows MCP hang on long-running tools (PR #231, fixes #46, #136): follow-up to v2.2.4. @dev-limucc reported on #136 that the
WindowsSelectorEventLoopPolicyfix from v2.2.4 was necessary but not sufficient — read-only tools worked, butbuild_or_update_graph_tool(full_rebuild=True)andembed_graph_toolstill hung indefinitely on Windows 11 / Python 3.14. Root cause: FastMCP 2.x dispatches sync handlers inline on the only event-loop thread, so handlers that run for more than a few seconds (especially those that spawn subprocesses or do CPU-bound inference) stop the loop from pumping stdin/stdout. Fix: converted the five heavy tools (build_or_update_graph_tool,run_postprocess_tool,embed_graph_tool,detect_changes_tool,generate_wiki_tool) toasync defand offloaded the blocking work viaasyncio.to_thread. The other 19 tools are fast SQLite-read paths and stay sync. Zero config, works on every platform. New regression tests assert the five tools are registered as coroutines AND that each one's source literally containsasyncio.to_threadas a defense-in-depth lock-in.
Additive feature release — new language parsers, new platform install target, MCP tool UX improvements, and out-of-tree graph storage. No breaking changes from v2.2.4.
- Elixir parser (PR #228, closes #112):
.exand.exsfiles now produce modules as Class nodes,def/defp/defmacro/defmacropas Function/Test nodes attached to their enclosing module,alias/import/require/useasIMPORTS_FROMedges, and everything else asCALLSedges. Internal call resolution walks intodo_blockbodies soMathHelpers.doublecorrectly resolves its call toCalculator.compute. - Objective-C parser (PR #227, closes #88):
.mfiles parse classes (@interface,@implementation,@protocol), instance and class methods,[receiver message:args]message expressions, C-stylemain(), and#import/#include. Multi-part selectors likeadd:to:keepaddas the canonical method name. - Bash/Shell parser (PR #227, closes #197):
.sh,.bash, and.zshfiles parse functions,commandinvocations asCALLS, andsource path/. pathasIMPORTS_FROMedges with path resolution when the target file exists. - Qwen Code as a supported MCP install platform (PR #227, closes #83):
code-review-graph install --platform qwenwrites a merged~/.qwen/settings.jsonusing the samemcpServersschema as Cursor/Windsurf — it does not clobber existing Qwen config. apply_refactor_tooldry-run mode (PR #228, closes #176): newdry_run: bool = Falseparameter on the MCP tool and underlyingapply_refactor()function. When true, returns a unified diff per file without touching disk and leaves therefactor_idvalid for a follow-up real apply. Multi-edit files now apply sequentially against updated content in both modes (fixes a subtle bug where separate edits on the same file could stomp each other).CRG_DATA_DIRenvironment variable (PR #228, closes #155): when set, replaces the default<repo>/.code-review-graphdirectory verbatim. Useful for ephemeral workspaces, Docker volumes, shared CI caches, and multi-repo orchestrators. Supported by the CLI, MCP tools, and the registry.CRG_REPO_ROOTenvironment variable (PR #228, closes #155):find_project_root()now checksCRG_REPO_ROOTbefore the usual git-root walk — useful for anyone scripting the CLI from a cwd outside the target repo.install --no-instructionsand-y/--yesflags (PR #228, closes #173): new flags oncode-review-graph installto opt out of theCLAUDE.md/AGENTS.md/.cursorrules/.windsurfrulesinjection entirely (--no-instructions) or auto-confirm it without an interactive prompt (-y/--yes). The CLI also now prints the list of files it will touch before writing, so even without--dry-runusers see what's coming.- Cloud embeddings stderr warning (PR #228, closes #174):
get_provider()now prints an explicit warning to stderr before returning a Google Gemini or MiniMax provider, explaining that source code will be sent to an external API.CRG_ACCEPT_CLOUD_EMBEDDINGS=1suppresses the warning for scripted workflows. The warning is on stderr only — it never writes to stdout or reads from stdin, so the MCP stdio transport remains uncorrupted. - TROUBLESHOOTING quick-reference (PR #228): new top section in
docs/TROUBLESHOOTING.mdcovering the four most common support questions — hook schema errors,command not foundafter pip install, project-vs-user scoping, and "built the graph but Claude Code doesn't see it".
- Multi-edit refactor correctness (PR #228): when a single
apply_refactorcall had multiple edits targeting the same file, the previous implementation re-read the file once per edit and could silently stomp earlier changes. The plan-computation step now groups edits by file and applies them sequentially against the updated content; this fix applies to both the real-write and the new dry-run path.
installandinitcommands now preview instruction-file targets before writing (no-op if nothing would change). This is always-on and does not require--dry-run.- Default embedding path remains fully local (
sentence-transformers); no behavior change unless you explicitly opt in to a cloud provider.
Nothing.
- The cloud-embedding stderr warning (#174) is a privacy improvement; it does not change the behavior of offline local embeddings, which remain the default.
- Nothing to do beyond
uvx --reinstall code-review-graphorpip install -U code-review-graph. If you're coming from v2.2.2 or earlier, re-runcode-review-graph installonce to pick up the v2.2.3 hook schema rewrite. CRG_DATA_DIRis optional — if you don't set it, graphs continue to live at<repo>/.code-review-graphas before.- VS Code extension v0.2.2 (from v2.2.4) still needs to be repackaged and republished separately; the PyPI
publish.ymlworkflow does not cover it.
- PR #204 (install preview, @lngyeen) — reimplemented cleanly in #228 with
isatty()-guarded confirmation. - PR #207 (
CRG_DATA_DIR/CRG_REPO_ROOT, @yashmewada9618) — reimplemented cleanly in #228 withoutinput()-on-stdio andmcp._local_onlyfragility. - PR #179 (cloud embeddings warning, @Bakul2006) — reimplemented cleanly in #228 with stderr-only messaging and no stdio reads.
Credit to @lngyeen, @yashmewada9618, and @Bakul2006 for the original designs.
Ships the 11 bugs from PR #222 plus the v2.2.3.1 smoke-test hotfixes, for users upgrading directly from v2.2.3 or earlier.
- fastmcp bumped from 1.0 → ≥2.14.0 (PR #222, fixes #139, #195): closes CVE-2025-62800 (XSS), CVE-2025-62801 (command injection via server_name), CVE-2025-66416 (Confused Deputy). Transitively drops the
docket → fakeredischain that was broken by aFakeConnection→FakeRedisConnectionrename in recent fakeredis releases (#195). The FastMCP public API (FastMCP(name, instructions=...),@mcp.tool(),@mcp.prompt(),mcp.run(transport="stdio")) is unchanged across the 1 → 2 bump, so no source changes were needed beyond the pin. All 24 tools verified to register on fastmcp 2.14.6 and round-trip real per-repo data via stdio MCP in a 6-repo smoke test.
- Windows build/embed hangs (PR #222, fixes #46, #136):
main()now setsWindowsSelectorEventLoopPolicybeforemcp.run()onsys.platform == "win32". The defaultProactorEventLoopon Windows Python 3.8+ deadlocks withProcessPoolExecutor(used byfull_build) over a stdio MCP transport — producing the silent "Synthesizing…" hangs onbuildandembed_graph_tool. This is a no-op on macOS/Linux. Note: the fix was applied blind; maintainer could not verify on Windows. Please open a fresh issue if you still see a hang on v2.2.4 Windows with eithersentence-transformersor Gemini providers. - Go method receivers (PR #222, fixes #190):
func (s *T) Foo()now attachesFootoTas a member (parent_name="T") with the usualCONTAINSedge instead of appearing as a top-level function. New_get_go_receiver_type()helper walks the method_declaration's first parameter_list to extract the receiver type name. - Dart parser — three bugs (PR #222, fixes #87):
- Dart
CALLSedges (_extract_dart_calls_from_children()) — tree-sitter-dart doesn't wrap calls in a singlecall_expressionnode; the pattern isidentifier + selector > argument_part. New walker handles both direct (print('x')) and method-chained (obj.foo()) shapes. - Dart
package:URI resolution in_do_resolve_module()—package:<pkgname>/<sub_path>now walks up to apubspec.yamlwhosename:declaration matches<pkgname>and resolves to<root>/lib/<sub_path>. inheritors_ofbare-vs-qualified name mismatch intools/query.py— falls back tosearch_edges_by_target_name(node.name, kind=...)forINHERITS/IMPLEMENTSwhen the qualified-name lookup returns nothing. Affects all languages (INHERITS targets are stored as bare strings for every language), not just Dart.
- Dart
- Nested
node_modulesand framework ignore defaults (PR #222, fixes #91):_should_ignore()now treats single-segment<dir>/**patterns as "this directory at any depth", sonode_modules/**also matchespackages/app/node_modules/react/index.jsinside monorepos. ExtendedDEFAULT_IGNORE_PATTERNSwith Laravel/Composer (vendor/**,bootstrap/cache/**,public/build/**), Ruby (.bundle/**), Gradle (.gradle/**,*.jar), Flutter/Dart (.dart_tool/**,.pub-cache/**), and genericcoverage/**,.cache/**. Deliberately did not addpackages/**orbin/**/obj/**— those are false positives in yarn/pnpm workspace monorepos and .NET source trees respectively. - Bare
except Exceptioncleanup (PR #222, fixes #194): Replaced with specific exception classes +logger.debug(...)in 11 files (cli.py,graph.py,migrations.py,parser.py,registry.py,tools/context.py,tsconfig_resolver.py,visualization.py,wiki.py,eval/benchmarks/search_quality.py). No behavioral change; debuggability improvement. - Visualization auto-collapse hiding all edges (PR #222, fixes #132):
visualization.pyno longer unconditionally auto-collapses every File node on page load. Auto-collapse now only kicks in above 2000 nodes — previously any graph above ~300 nodes would silently hide every CALLS/IMPORTS/INHERITS edge because they connect Functions/Classes nested inside the collapsed Files. evalcommand crashes onyaml.safe_load(PR #222, fixes #212):eval.runner.load_all_configs()now calls_require_yaml()before reading YAML, so users withoutcode-review-graph[eval]installed getImportError: pyyaml is required: pip install code-review-graph[eval]instead ofAttributeError: 'NoneType' object has no attribute 'safe_load'.
better-sqlite3bumped 11.x → 12.x (PR #222, fixes #218): VS Code 1.115 ships Electron 39 / V8 14.2 which removedv8::Context::GetIsolate(), the C++ API used bybetter-sqlite3@11. The extension couldn't activate at all — every command was undefined.better-sqlite3@12.4.1+(installs 12.8.0) uses the new V8 API and ships Electron 39 prebuilds.@types/better-sqlite3: ^7.6.8 → ^7.6.13, plus type-import adjustments insrc/backend/sqlite.tsfor theNode16module resolution and the new CJSexport =types. Extension version bumped to 0.2.2. Remember to repackage and republish the.vsix— the existingpublish.ymlworkflow only covers PyPI.
serve --repo <X>is now honored by all 24 MCP tools (was only read byget_docs_section_tool). See #223.- Wiki slug collisions no longer silently overwrite pages (~70% data loss on real repos). See #223.
uvx --reinstall code-review-graphorpip install -U code-review-graph, then re-runcode-review-graph install(the 2.2.3 hook-schema rewrite is still a requirement if you're coming from 2.2.2 or earlier).- VS Code extension needs to be repackaged + republished separately; the Python release does not include it.
Hotfix on top of 2.2.3 for two bugs surfaced by a full first-time-user smoke test against six real OSS repos (express, fastapi, flask, gin, httpx, next.js).
serve --repo <X>was ignored by 21 of 24 MCP tools (PR #223):main.pycaptured the--repoCLI flag into_default_repo_root, but onlyget_docs_section_toolread it. The other 21@mcp.tool()wrappers all tookrepo_root: Optional[str] = Noneand passed that straight through to the impl, which fell back tofind_repo_root()from cwd. The real-world blast radius is small — theinstallcommand writes.mcp.jsonwithout a--repoflag and Claude Code launches the server withcwd=<repo>— but anyone scriptingservemanually or running a multi-repo orchestrator would silently get the wrong graph. Added a single_resolve_repo_root()helper with explicit precedence (client arg >--repoflag >None → cwd) and threaded it through all 24 wrappers. New unit tests cover the precedence rules.- Wiki slug collisions silently overwrote pages (PR #223):
_slugify()folds non-alphanumerics to dashes and truncates to 80 chars, so similar community names collided ("Data Processing","data processing","Data Processing"all →data-processing.md).generate_wiki()wrote each community to<slug>.mdregardless, so later iterations overwrote earlier files while the counter reported them as "updated". On the express smoke test this was ~70% silent data loss (32 real files vs 107 claimed pages). Fixed by tracking used slugs per-run and appending-2,-3, … until unique. Every community now gets its own page; the counter matches the physical file count;get_wiki_page()still resolves by name via the existing partial-match fallback. New regression test monkey-patches three colliding names and asserts no content loss.
- Claude Code hook schema (PR #208, fixes #97, #138, #163, #168, #172, #182, #188, #191, #201):
generate_hooks_config()now emits the valid v1.x+ Claude Code schema — every hook entry hasmatcher+ a nestedhooks: [{type, command, timeout}]array, and timeouts are in seconds. The invalidPreCommitevent has been removed; pre-commit checks are now installed as a real git hook viainstall_git_hook(). Users upgrading from 2.2.2 must re-runcode-review-graph installto rewrite.claude/settings.json. - SQLite transaction nesting (PR #205, fixes #110, #135, #181):
GraphStore.__init__now connects withisolation_level=None, disabling Python's implicit transactions that were the root cause ofsqlite3.OperationalError: cannot start a transaction within a transactiononupdate.store_file_nodes_edgesadds a defensivein_transactionflush beforeBEGIN IMMEDIATE. - Go method receivers (PR #166):
_extract_name_from_nodenow resolves Go method names fromfield_identifierinsidemethod_declaration, fixing method names that were previously picked up as the result type (e.g.int64) instead of the method name. - UTF-8 decode errors in
detect_changes(PR #170, fixes #169): Diff parsing now useserrors="replace"so diffs containing binary files no longer crash the tool. --platformtarget scope (PR #142, fixes #133):code-review-graph install --platform <target>now correctly filters skills, hooks, and instruction files so you only get configuration for the requested platform.- Large-repo community detection hangs (PR #213, PR #183): Removed recursive sub-community splitting, capped Leiden at
n_iterations=2, and batchedstore_communitieswrites. 100k+ node graphs no longer hang in_compute_summaries. - CI: ruff lint +
tomllibon Python 3.10 (PR #220) —tests/test_skills.pynow uses a conditionaltomlibackport on 3.10,N806/E501/W291fixes inskills.py/communities.py/parser.py, and the embeddednoqareference invisualization.pywas rephrased so ruff stops parsing it as a directive. - Missing dev dependencies (PR #159):
pytest-covadded to dev extras, 50 ruff errors swept, one failing test fixed. - JSX component CALLS edges (PR #154): JSX component usage now produces CALLS edges so component-to-component relationships appear in the graph.
- Codex platform install support (PR #177):
code-review-graph install --platform codexappends amcp_servers.code-review-graphsection to~/.codex/config.tomlwithout overwriting existing Codex settings. - Luau language support (PR #165, closes #153): Roblox Luau (
.luau) parsing — functions, classes, local functions, requires, tests. - REFERENCES edge type (PR #217): New edge kind for symbol references that aren't direct calls (map/dispatch lookups, string-keyed handlers), including Python and TypeScript patterns.
recurse_submodulesbuild option (PR #215): Build/update can now optionally recurse into git submodules..gitignoredefault for.code-review-graph/(PR #185): Fresh installs automatically add the SQLite DB directory to.gitignoreso the database isn't accidentally committed.- Clearer gitignore docs (PR #171, closes #157): Documentation now spells out that
code-review-graphalready respects.gitignoreviagit ls-files.
- Community detection is now bounded — large repos complete in reasonable time instead of hanging indefinitely.
install_hooksnow merges instead of overwriting (PR #203, fixes #114):install_hooks()previously useddict.update()which clobbered any user-defined hooks in.claude/settings.json. Now merges new entries into existing hook arrays, preserving user hooks. Creates a backup (settings.json.bak) before modification.
- Kotlin call extraction:
simple_identifier+navigation_expressionsupport for Kotlin method calls (PR #107) - JUnit/Kotlin test detection: Annotation-based test classification (
@Test,@ParameterizedTest, etc.) for Java/Kotlin/C# (PR #107)
- Windows encoding crash: All
write_text/read_textcalls inskills.pynow useencoding='utf-8'explicitly (PR #152, fixes #147, #148) - Invalid
--quietflag in hooks: Removed non-existent--quietand--jsonflags from generated hook commands (PR #152, fixes #149)
- Untracked
.claude-plugin/directory and added to.gitignore - GitHub issue triage: responded to 30+ issues, closed 14, reviewed 24 PRs
- Parallel parsing:
ProcessPoolExecutorfor 3-5x faster builds (CRG_PARSE_WORKERS,CRG_SERIAL_PARSE) - Lazy post-processing:
postprocess="full"|"minimal"|"none"parameter,run_postprocessMCP tool + CLI command - SQLite-native BFS: Recursive CTE replaces NetworkX for impact analysis (
CRG_BFS_ENGINE) - Configurable limits:
CRG_MAX_IMPACT_NODES,CRG_MAX_IMPACT_DEPTH,CRG_MAX_BFS_DEPTH,CRG_MAX_SEARCH_RESULTS - Multi-hop dependents: N-hop
find_dependents()withCRG_DEPENDENT_HOPS(default 2) and 500-file cap - Token-efficient output:
detail_level="minimal"on 8 tools for 40-60% token reduction get_minimal_contexttool: Ultra-compact entry point (~100 tokens) with task-based tool routing- Token-efficient prompts: All 5 MCP prompts rewritten with minimal-first workflows
- Incremental flow/community updates:
incremental_trace_flows(),incremental_detect_communities() - Visualization aggregation: Community/file/auto modes with drill-down for large graphs (
--mode) - Token-efficiency benchmarks: 5 workflow benchmarks in
eval/token_benchmark.py - DB schema v6: Pre-computed
community_summaries,flow_snapshots,risk_indextables - Token Efficiency Rules in all skill templates and CLAUDE.md
- CLI
build/updatesupport--skip-flows,--skip-postprocessflags - PostToolUse hook uses
--skip-flowsfor faster incremental updates - VS Code extension schema version bumped to v6
- mypy type errors in parallel parsing and context tool
- Bandit false positive on prompt preamble string
- Import sorting in graph.py, main.py, tools/init.py
- Unused imports cleaned up in cli.py
- Gitignore: untrack
marketing-diagram.excalidraw,evaluate/results/,evaluate/reports/ - Updated FEATURES.md, LLM-OPTIMIZED-REFERENCE.md, CHANGELOG.md for v2.2.1
- Jupyter notebook parsing: Parse
.ipynbfiles — extract functions, classes, imports across Python, R, and SQL cells - Databricks notebook parsing: Parse Databricks
.pynotebook exports with# COMMAND ----------cell boundaries - Lua language support: Full parsing for
.luafiles (functions, local functions, method calls, requires) — 20th language - Perl XS support: Parse
.xsfiles with improved Perl call detection and test coverage - Zero-config onboarding:
installnow sets up skills, hooks, and CLAUDE.md by default so the graph is used automatically - Platform rule injection: Graph instructions injected into all platform rule files (CLAUDE.md, .cursorrules, etc.) on install
- Smart install detection: Auto-detects whether installed via uvx or pip and generates correct
.mcp.json --platform claude-codealias: Accepts bothclaudeandclaude-codeas platform names
- JS/TS arrow functions indexed:
const foo = () => {}andconst bar = function() {}now correctly appear as nodes (#66) importers_ofpath resolution: Normalized withresolve()to match stored edge targets (#65)- Custom embedding models: Support for custom model architectures and restored model param wiring in search (#79)
- 12 new features: flows, communities, hybrid search, change analysis, refactoring, hints, prompts, skills, wiki, multi-repo registry, migrations, eval framework
- 14 new modules (~10,000 lines):
flows.py,communities.py,search.py,changes.py,refactor.py,hints.py,prompts.py,skills.py,wiki.py,registry.py,migrations.py,eval/ - 15 new MCP tools:
list_flows,get_flow,get_affected_flows,list_communities,get_community,get_architecture_overview,detect_changes,refactor,apply_refactor,generate_wiki,get_wiki_page,list_repos,cross_repo_search,find_large_functions,semantic_search_nodes - 5 MCP prompts:
review_changes,architecture_map,debug_issue,onboard_developer,pre_merge_check - 7 new CLI commands:
detect-changes,wiki,eval,register,unregister,repos,install --skills/--hooks/--all - Interactive visualization upgrade: Detail panel, community coloring, flow path highlighting, search-to-zoom, kind filters
- Fix path traversal in wiki page reader
- Add regex allowlist for git ref validation
- Add explicit SSL context for MiniMax API
- Fix git diff argument ordering (broke incremental updates)
- Fix
node_qualified_nameschema mismatch in wiki flow query - Batch N+1 queries in
get_impact_radiusand risk scoring
- Decompose
_extract_from_treeinto 6 focused methods - Add 17 public query methods to
GraphStore - Split
tools.pyinto 10 themed sub-modules
- Vue SFC parsing: Parse
.vueSingle File Components by extracting<script>blocks with automaticlang="ts"detection - Solidity support: Full parsing for
.solfiles (functions, events, modifiers, inheritance) find_large_functions_tool: New MCP tool to find functions, classes, or files exceeding a line-count threshold- Call target resolution: Bare call targets resolved to qualified names using same-file definitions (
_resolve_call_targets) - Multi-word AND search:
search_nodesnow requires all words to match (case-insensitive) - Impact radius pagination:
get_impact_radiusreturnstruncatedflag,total_impactedcount, and acceptsmax_resultsparameter
- Language count updated from 12 to 14 across all documentation
- MCP tool count updated from 8 to 9 across all documentation
- VS Code extension updated to v0.2.0 with 5 new commands documented
- Test assertions updated to handle qualified call targets from
_resolve_call_targets
- Parser recursion guard: Added
_MAX_AST_DEPTH = 180limit to_extract_from_tree()preventing stack overflow on deeply nested ASTs - Module cache bound: Added
_MODULE_CACHE_MAX = 15_000with automatic eviction to prevent unbounded memory growth in_module_file_cache - Embeddings thread safety: Added
check_same_thread=FalsetoEmbeddingStoreSQLite connection - Embeddings retry logic: Added
_call_with_retry()with exponential backoff for Google Gemini API calls - Visualization XSS hardening: Added
</to<\/replacement in JSON serialization to prevent script injection - CLI error handling: Split broad
exceptinto specificjson.JSONDecodeErrorand(KeyError, TypeError)handlers - Git timeout: Made configurable via
CRG_GIT_TIMEOUTenvironment variable (default 30s)
- Governance files: Added CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md
- Project URLs: Added Homepage, Repository, Issues, Changelog URLs to pyproject.toml metadata
- C# parsing broken: Renamed language identifier from
c_sharptocsharpto matchtree-sitter-language-pack's actual identifier. Previously, all C# files were silently skipped because_get_parser()swallowed theLookupError.
- Add missing
max_nodesparameter toget_impact_radiusmethod signature (causedNameErrorat runtime) - Fix
.gitignoretest assertion to match expanded comment format
- Prompt injection mitigation: Node names are now sanitized (control characters stripped, length capped at 256) before appearing in MCP tool responses, preventing graph-laundered prompt injection attacks
- Path traversal protection:
repo_rootparameter now validates that the target directory contains a.gitor.code-review-graphdirectory, preventing arbitrary file exfiltration via MCP tools - VSCode RCE fix:
cliPathsetting is now scoped tomachinelevel only, preventing malicious workspace settings from pointing to attacker-controlled binaries - XSS fix in visualization:
escH()now escapes quotes and backticks in addition to angle brackets, closing stored XSS via crafted node names in generated HTML - SRI for CDN assets: D3.js script tag now includes
integrityandcrossoriginattributes to prevent CDN compromise - Secure nonce generation: VSCode webview CSP nonces now use
crypto.randomBytes()instead ofMath.random() - Symlink protection: Build, watch mode, and file collection now skip symbolic links to prevent parsing files outside the repository
- TOCTOU elimination: File bytes are now read once, then hashed and parsed from the same buffer, closing the time-of-check-to-time-of-use gap
- Thread-safe NetworkX cache: Added
threading.Lockaround graph cache reads/writes to prevent race conditions between watch mode and MCP request handling - BFS resource limits: Impact radius traversal now caps at 500 nodes to prevent memory exhaustion on dense graphs
- SQL parameter batching:
get_edges_amongnow batches queries to stay under SQLite's variable limit on large node sets - Database path leakage: Improved
.gitignoreinside.code-review-graph/with explicit warnings about absolute paths in the database
- Pinned dependency bounds: All dependencies now have upper-bound version constraints to mitigate supply-chain risks
- Watch mode thread safety: SQLite connections now use
check_same_thread=Falsefor Python 3.10/3.11 compatibility with watchdog's background threads - Full rebuild stale data:
full_buildnow purges nodes/edges from files deleted since last build - Removed unused dependency:
gitpythonwas listed in dependencies but never imported — removed to shrink install footprint - Stale Docker reference: Removed non-existent Docker image suggestion from Python version check
installcommand — primary entry point for new users (code-review-graph install).initremains as an alias for backwards compatibility.--dry-runflag oninstall/init— shows what would be written without modifying files- PyPI publish workflow — GitHub releases now automatically publish to PyPI via API token
- Professional README — complete rewrite with real benchmark data:
- Code reviews: 6.8x average token reduction (tested on httpx, FastAPI, Next.js)
- Live coding tasks: 14.1x average, up to 49.1x on large repos
- README restructured around the install-and-forget user experience
- CLI banner now shows
installas the primary command
- Portable MCP config:
initnow generatesuvx-based.mcp.jsoninstead of absolute Python paths — works on any machine withuvinstalled - Removed
_safe_pathsymlink workaround (no longer needed withuvx)
- SessionStart hook — Claude Code now automatically prefers graph MCP tools over full codebase scans at the start of every session, saving tokens on general queries
homepageandauthor.urlfields in plugin.json for marketplace discoverability
- plugin.json schema: renamed
tagstokeywords, removed invalidskillspath (auto-discovered from default location) - Removed screenshot placeholder section from README
- Critical: Incremental hash comparison bug —
file_hashread from wrong field, causing every file to re-parse - Watch mode
on_deletedhandler now filters by ignore patterns - Removed dead code in
full_buildand duplicatemain()inincremental.py get_staged_and_unstagedhandles git renamed files (R old -> new)- TROUBLESHOOTING.md hook config path corrected
- Parser: C/C++ support — full node extraction (structs, classes, functions, includes, calls, inheritance)
- Parser: name extraction fixes for Kotlin/Swift (
simple_identifier), Ruby (constant), C/C++ nestedfunction_declarator GraphStorecontext manager (__enter__/__exit__)get_all_edges()andget_edges_among()public methods onGraphStore- NetworkX graph caching with automatic invalidation on writes
- Subprocess timeout (30s) on all git calls
- Progress logging every 50 files in full build
- SHA-256 hashing in embeddings (replaced MD5)
- Chunked embedding search (
fetchmany(500)) - Batch edge collection in
get_impact_radius(single SQL query) - ARIA labels throughout D3.js visualization
- CI: Coverage enforcement (
--cov-fail-under=50), bandit security scanning, mypy type checking - Tests:
test_incremental.py(24 tests),test_embeddings.py(16 tests) - Test fixtures: C, C++, C#, Ruby, PHP, Kotlin, Swift with multilang test classes
- Docs: API response schemas in COMMANDS.md, ignore patterns in USAGE.md
initnow auto-creates symlinks when paths contain spaces (macOS iCloud, OneDrive, etc.)build,status,visualize,watchwork without a git repository (falls back to cwd)- Skills discoverable via plugin.json (
namefield added to SKILL.md frontmatter)
- File organization: All generated files now live in
.code-review-graph/directory instead of repo root- Auto-created
.gitignoreinside the directory prevents accidental commits - Automatic migration from legacy
.code-review-graph.dbat repo root
- Auto-created
- Visualization: start collapsed: Only File nodes visible on load; click to expand children
- Visualization: search bar: Filter nodes by name or qualified name in real-time
- Visualization: edge type toggles: Click legend items to show/hide edge types (Calls, Imports, Inherits, Contains)
- Visualization: scale-aware layout: Force simulation adapts charge, distance, and decay for large graphs (300+ nodes)
- Database path:
.code-review-graph.db→.code-review-graph/graph.db - HTML visualization path:
.code-review-graph.html→.code-review-graph/graph.html .code-review-graph/**added to default ignore patterns (prevents self-indexing)
references/directory (duplicate ofdocs/, caused stale path references)agents/directory (unused, not wired into any code)settings.jsonat repo root (decorative, not loaded by code)
initcommand: automatic.mcp.jsonsetup for Claude Code integrationvisualizecommand: interactive D3.js force-directed graph visualizationservecommand: start MCP server directly from CLI
- Comprehensive documentation overhaul across all reference files
- Universal installation: now works with
pip install code-review-graph[embeddings]on Python 3.10+ - CLI entry point (
code-review-graphcommand works after normal pip install) - Clear Python version check with helpful Docker fallback for older Python users
- Improved README installation section with one-command + Docker option
- Minimum Python requirement lowered from 3.11 → 3.10 (covers ~90% of users)
- Installation friction for most developers