code-review-graph-codeblackwell 2.4.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/PKG-INFO +58 -24
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/README.md +52 -19
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/__init__.py +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/changes.py +128 -7
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/cli.py +592 -61
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/communities.py +235 -21
- code_review_graph_codeblackwell-3.0.0/code_review_graph/config_keys.py +33 -0
- code_review_graph_codeblackwell-3.0.0/code_review_graph/constants.py +73 -0
- code_review_graph_codeblackwell-3.0.0/code_review_graph/css_resolver.py +155 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/daemon.py +67 -6
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/daemon_cli.py +12 -3
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/embeddings.py +157 -23
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/enrich.py +8 -5
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/fastapi.yaml +7 -7
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/runner.py +16 -2
- code_review_graph_codeblackwell-3.0.0/code_review_graph/event_resolver.py +122 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/exports.py +39 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/flows.py +16 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/graph.py +567 -243
- code_review_graph_codeblackwell-3.0.0/code_review_graph/hcl_resolver.py +110 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/incremental.py +197 -309
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/main.py +183 -119
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/migrations.py +13 -0
- code_review_graph_codeblackwell-3.0.0/code_review_graph/parser.py +14878 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/postprocessing.py +72 -6
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/refactor.py +32 -7
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/search.py +19 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/skills.py +289 -57
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/__init__.py +2 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/_common.py +115 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/build.py +131 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/docs.py +3 -2
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/query.py +289 -91
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/review.py +0 -8
- code_review_graph_codeblackwell-3.0.0/code_review_graph/uninstall.py +1265 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/visualization.py +76 -45
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/COMMANDS.md +5 -4
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/FAQ.md +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/FEATURES.md +2 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/GITHUB_ACTION.md +34 -10
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/LLM-OPTIMIZED-REFERENCE.md +2 -2
- code_review_graph_codeblackwell-3.0.0/docs/MAINTAINER_RECONCILIATION_2026-07-17.md +291 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/TROUBLESHOOTING.md +10 -10
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/USAGE.md +27 -2
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/architecture.md +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/schema.md +11 -23
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/pyproject.toml +6 -5
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/debug-issue/SKILL.md +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/explore-codebase/SKILL.md +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/refactor-safely/SKILL.md +1 -1
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/review-changes/SKILL.md +1 -1
- code_review_graph_codeblackwell-2.4.0/code_review_graph/constants.py +0 -23
- code_review_graph_codeblackwell-2.4.0/code_review_graph/parser.py +0 -8058
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/README.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/post-checkout +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/post-merge +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/pre-commit +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/pre-push +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/prepare-commit-msg +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.gitignore +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/LICENSE +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code-review-graph-vscode/LICENSE +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code-review-graph-vscode/README.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/__main__.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/analysis.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/context_savings.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/custom_languages.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/__init__.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/__init__.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/agent_baseline.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/build_performance.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/flow_completeness.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/impact_accuracy.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/multi_hop_retrieval.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/search_quality.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/token_efficiency.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/code-review-graph.yaml +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/express.yaml +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/flask.yaml +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/gin.yaml +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/httpx.yaml +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/reporter.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/scorer.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/token_benchmark.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/graph_diff.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/hints.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/jedi_resolver.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/memory.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/prompts.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/registry.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/rescript_resolver.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/spring_resolver.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/temporal_resolver.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/token_benchmark.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/analysis_tools.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/community_tools.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/context.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/flows_tools.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/refactor_tools.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/registry_tools.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tsconfig_resolver.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/wiki.py +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/CUSTOM_LANGUAGES.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/INDEX.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/LEGAL.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/REPRODUCING.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/ROADMAP.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/hooks/hooks.json +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/hooks/session-start.sh +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/build-graph/SKILL.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/review-delta/SKILL.md +0 -0
- {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/review-pr/SKILL.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-review-graph-codeblackwell
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Local-first knowledge graph for token-efficient code review through MCP and CLI. Fork of tirth8205/code-review-graph with additional fixes; CLI and MCP server remain `code-review-graph`.
|
|
5
5
|
Project-URL: Homepage, https://github.com/CodeBlackwell/code-review-graph-codeblackwell
|
|
6
6
|
Project-URL: Repository, https://github.com/CodeBlackwell/code-review-graph-codeblackwell
|
|
@@ -26,10 +26,11 @@ Requires-Python: >=3.10
|
|
|
26
26
|
Requires-Dist: fastmcp<4,>=3.2.4
|
|
27
27
|
Requires-Dist: mcp<2,>=1.0.0
|
|
28
28
|
Requires-Dist: networkx<4,>=3.2
|
|
29
|
+
Requires-Dist: pyyaml<7,>=6.0
|
|
29
30
|
Requires-Dist: tomli<3,>=2.0.0; python_version < '3.11'
|
|
30
31
|
Requires-Dist: tree-sitter-language-pack<1,>=0.3.0
|
|
31
32
|
Requires-Dist: tree-sitter<1,>=0.23.0
|
|
32
|
-
Requires-Dist: watchdog<
|
|
33
|
+
Requires-Dist: watchdog<7,>=4.0.0
|
|
33
34
|
Provides-Extra: all
|
|
34
35
|
Requires-Dist: igraph>=0.11.0; extra == 'all'
|
|
35
36
|
Requires-Dist: jedi>=0.19.2; extra == 'all'
|
|
@@ -37,18 +38,18 @@ Requires-Dist: matplotlib>=3.7.0; extra == 'all'
|
|
|
37
38
|
Requires-Dist: numpy<3,>=1.26; extra == 'all'
|
|
38
39
|
Requires-Dist: ollama>=0.1.0; extra == 'all'
|
|
39
40
|
Requires-Dist: pyyaml>=6.0; extra == 'all'
|
|
40
|
-
Requires-Dist: sentence-transformers<
|
|
41
|
+
Requires-Dist: sentence-transformers<6,>=3.0.0; extra == 'all'
|
|
41
42
|
Provides-Extra: communities
|
|
42
43
|
Requires-Dist: igraph>=0.11.0; extra == 'communities'
|
|
43
44
|
Provides-Extra: dev
|
|
44
|
-
Requires-Dist: pytest-asyncio<
|
|
45
|
+
Requires-Dist: pytest-asyncio<2,>=0.23; extra == 'dev'
|
|
45
46
|
Requires-Dist: pytest-cov<8,>=4.0; extra == 'dev'
|
|
46
47
|
Requires-Dist: pytest<9,>=8.0; extra == 'dev'
|
|
47
48
|
Requires-Dist: ruff<1,>=0.3.0; extra == 'dev'
|
|
48
49
|
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
|
|
49
50
|
Provides-Extra: embeddings
|
|
50
51
|
Requires-Dist: numpy<3,>=1.26; extra == 'embeddings'
|
|
51
|
-
Requires-Dist: sentence-transformers<
|
|
52
|
+
Requires-Dist: sentence-transformers<6,>=3.0.0; extra == 'embeddings'
|
|
52
53
|
Provides-Extra: enrichment
|
|
53
54
|
Requires-Dist: jedi>=0.19.2; extra == 'enrichment'
|
|
54
55
|
Provides-Extra: eval
|
|
@@ -62,6 +63,8 @@ Description-Content-Type: text/markdown
|
|
|
62
63
|
|
|
63
64
|
<h1 align="center">code-review-graph</h1>
|
|
64
65
|
|
|
66
|
+
<a href="https://trendshift.io/repositories/23329?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-23329" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/23329" alt="tirth8205%2Fcode-review-graph | Trendshift" width="250" height="55"/></a>
|
|
67
|
+
|
|
65
68
|
<p align="center">
|
|
66
69
|
<strong>Stop burning tokens. Start reviewing smarter.</strong>
|
|
67
70
|
</p>
|
|
@@ -123,7 +126,7 @@ code-review-graph build # parse your codebase
|
|
|
123
126
|
One command sets up everything. `install` detects which AI coding tools you have, writes the correct MCP configuration for each one, installs platform-native hooks/skills where supported, and injects graph-aware instructions into your platform rules. It auto-detects whether you installed via `uvx` or `pip`/`pipx` and generates the right config. Restart your editor/tool after installing.
|
|
124
127
|
|
|
125
128
|
<p align="center">
|
|
126
|
-
<img src="diagrams/diagram8_supported_platforms.png" alt="One Install, Every Platform: auto-detects Codex, Claude Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, and GitHub Copilot" width="85%" />
|
|
129
|
+
<img src="diagrams/diagram8_supported_platforms.png" alt="One Install, Every Platform: auto-detects Codex, Claude Code, CodeBuddy Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, and GitHub Copilot" width="85%" />
|
|
127
130
|
</p>
|
|
128
131
|
|
|
129
132
|
To target a specific platform:
|
|
@@ -136,10 +139,27 @@ code-review-graph install --platform gemini-cli # configure only Gemini CLI
|
|
|
136
139
|
code-review-graph install --platform kiro # configure only Kiro
|
|
137
140
|
code-review-graph install --platform copilot # configure only GitHub Copilot (VS Code)
|
|
138
141
|
code-review-graph install --platform copilot-cli # configure only GitHub Copilot CLI
|
|
142
|
+
code-review-graph install --platform codebuddy # configure only CodeBuddy Code
|
|
139
143
|
```
|
|
140
144
|
|
|
141
145
|
Requires Python 3.10+. For the best experience, install [uv](https://docs.astral.sh/uv/) (the MCP config will use `uvx` if available, otherwise falls back to the `code-review-graph` command directly).
|
|
142
146
|
|
|
147
|
+
To remove CRG from a Git or SVN project, use the symmetric uninstall command
|
|
148
|
+
from anywhere inside its working tree. The target is normalized to the working
|
|
149
|
+
tree root, and non-repository directories are refused. It removes only
|
|
150
|
+
CRG-owned files and entries; unrelated MCP servers, hooks, skills, and JSONC
|
|
151
|
+
comments remain untouched. Shared configuration changes use atomic replacement
|
|
152
|
+
so a failed write leaves the original file intact.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
code-review-graph uninstall --dry-run # preview every action; write nothing
|
|
156
|
+
code-review-graph uninstall # preview, ask for confirmation, then apply
|
|
157
|
+
code-review-graph uninstall --yes # apply without prompting
|
|
158
|
+
code-review-graph uninstall --all-repos # also clean every registered repository
|
|
159
|
+
code-review-graph uninstall --keep-data # remove integrations but keep graph databases
|
|
160
|
+
code-review-graph uninstall --keep-user-configs --repo . # clean this project only
|
|
161
|
+
```
|
|
162
|
+
|
|
143
163
|
Then open your project and ask your AI assistant:
|
|
144
164
|
|
|
145
165
|
```
|
|
@@ -191,7 +211,12 @@ Large monorepos are where token waste is most painful. The graph cuts through th
|
|
|
191
211
|
<img src="diagrams/diagram9_language_coverage.png" alt="Language coverage organized by category: Web, Backend, Systems, Mobile, Scripting, Config, plus Jupyter and Databricks notebook support" width="90%" />
|
|
192
212
|
</p>
|
|
193
213
|
|
|
194
|
-
Parser support covers functions, classes, imports, call sites, inheritance, and test detection across the current parser surface, using Tree-sitter where available and targeted fallbacks where needed. Current support includes Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL,
|
|
214
|
+
Parser support covers functions, classes, imports, call sites, inheritance, and test detection across the current parser surface, using Tree-sitter where available and targeted fallbacks where needed. Current support includes Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, VB.NET, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL, Terraform/OpenTofu structure (`.tf`; generic `.hcl` files are recognized as file nodes), Ansible playbooks/roles/tasks, Vue/Svelte SFCs, Astro files parsed through the TypeScript parser, Jupyter/Databricks notebooks (`.ipynb`), and Perl XS files (`.xs`). Generic YAML is not treated as source code.
|
|
215
|
+
|
|
216
|
+
PHP projects additionally get repository-bounded Composer PSR-4 resolution,
|
|
217
|
+
Blade template references, and Laravel Route/Eloquent semantic edges when the
|
|
218
|
+
source includes explicit framework imports, model inheritance, and receiver
|
|
219
|
+
evidence.
|
|
195
220
|
|
|
196
221
|
### Add your own language (no fork needed)
|
|
197
222
|
|
|
@@ -226,7 +251,7 @@ jobs:
|
|
|
226
251
|
review:
|
|
227
252
|
runs-on: ubuntu-latest
|
|
228
253
|
steps:
|
|
229
|
-
- uses: actions/checkout@
|
|
254
|
+
- uses: actions/checkout@v7
|
|
230
255
|
- uses: tirth8205/code-review-graph@v2.3.6
|
|
231
256
|
with:
|
|
232
257
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -310,7 +335,7 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
310
335
|
- **Impact "recall 1.0" is graph-derived and circular:** the historical ground truth comes from the same graph edges the predictor walks, so it is an upper bound by construction. The honest co-change mode (grade against files actually co-changed in the same commit) is measured alongside it; expect those numbers to be substantially lower.
|
|
311
336
|
- **Small single-file changes:** Graph context can exceed naive file reads for trivial edits (see express results above). The overhead is the structural metadata that enables multi-file analysis.
|
|
312
337
|
- **Search quality (MRR 0.35):** Keyword search finds the right result in the top-4 for most queries, but ranking needs improvement. Express queries return 0 hits due to module-pattern naming.
|
|
313
|
-
- **Flow detection (33% recall):**
|
|
338
|
+
- **Flow detection (33% recall):** Framework and conventional entry patterns are strongest for Python and PHP/Laravel. JavaScript and Go flow detection needs work.
|
|
314
339
|
- **Precision vs recall trade-off:** Impact analysis is deliberately conservative. It flags files that *might* be affected, which means some false positives in large dependency graphs.
|
|
315
340
|
|
|
316
341
|
---
|
|
@@ -320,7 +345,8 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
320
345
|
| Feature | Details |
|
|
321
346
|
|---------|---------|
|
|
322
347
|
| **Incremental updates** | Re-parses only changed files. Subsequent updates complete in under 2 seconds. |
|
|
323
|
-
| **Broad language + notebook support** | Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL,
|
|
348
|
+
| **Broad language + notebook support** | Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, VB.NET, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL, Terraform/OpenTofu structure (`.tf`; generic `.hcl` files are file-only), Ansible playbooks/roles/tasks, Vue/Svelte SFCs, Astro files parsed through the TypeScript parser, Jupyter/Databricks (.ipynb), and Perl XS (.xs) |
|
|
349
|
+
| **Framework-aware PHP parsing** | Repository-bounded Composer PSR-4 imports, Blade template references, and evidence-gated Laravel Route-to-controller and Eloquent relationship edges |
|
|
324
350
|
| **Blast-radius analysis** | Shows which functions, classes, and files are likely affected by a change |
|
|
325
351
|
| **Auto-update hooks** | Hooks and watch mode can update the graph on file saves and supported commit hooks |
|
|
326
352
|
| **Semantic search** | Optional vector embeddings via sentence-transformers, Google Gemini, MiniMax, or any OpenAI-compatible endpoint (real OpenAI, Azure, new-api, LiteLLM, vLLM, LocalAI) |
|
|
@@ -375,11 +401,13 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
375
401
|
```bash
|
|
376
402
|
code-review-graph install # Auto-detect and configure all platforms
|
|
377
403
|
code-review-graph install --platform <name> # Target a specific platform
|
|
404
|
+
code-review-graph uninstall --dry-run # Preview safe removal of installed artifacts
|
|
378
405
|
code-review-graph build # Parse entire codebase
|
|
379
406
|
code-review-graph update # Incremental update (changed files only)
|
|
380
407
|
code-review-graph status # Graph statistics
|
|
381
408
|
code-review-graph watch # Auto-update on file changes
|
|
382
409
|
code-review-graph visualize # Generate interactive HTML graph
|
|
410
|
+
code-review-graph visualize --format json # Export local graph data as JSON
|
|
383
411
|
code-review-graph visualize --format graphml # Export as GraphML
|
|
384
412
|
code-review-graph visualize --format svg # Export as SVG
|
|
385
413
|
code-review-graph visualize --format obsidian # Export as Obsidian vault
|
|
@@ -398,6 +426,10 @@ code-review-graph eval # Run evaluation benchmarks
|
|
|
398
426
|
code-review-graph serve # Start MCP server
|
|
399
427
|
```
|
|
400
428
|
|
|
429
|
+
JSON exports stay inside the local graph data directory, which Git ignores by
|
|
430
|
+
default. They can contain absolute paths and code-structure metadata, so inspect
|
|
431
|
+
and sanitize an export before publishing it outside your machine.
|
|
432
|
+
|
|
401
433
|
</details>
|
|
402
434
|
|
|
403
435
|
<details>
|
|
@@ -543,13 +575,13 @@ Note: in git repos, only tracked files are indexed (`git ls-files`), so gitignor
|
|
|
543
575
|
Optional dependency groups:
|
|
544
576
|
|
|
545
577
|
```bash
|
|
546
|
-
pip install code-review-graph[embeddings] # Local vector embeddings (sentence-transformers)
|
|
547
|
-
pip install code-review-graph[google-embeddings] # Google Gemini embeddings
|
|
548
|
-
pip install code-review-graph[communities] # Community detection (igraph)
|
|
549
|
-
pip install code-review-graph[enrichment] # Python call-resolution enrichment (Jedi)
|
|
550
|
-
pip install code-review-graph[eval] # Evaluation benchmarks (matplotlib)
|
|
551
|
-
pip install code-review-graph[wiki] # Wiki generation with LLM summaries (ollama)
|
|
552
|
-
pip install code-review-graph[all] # All optional dependencies
|
|
578
|
+
pip install "code-review-graph[embeddings]" # Local vector embeddings (sentence-transformers)
|
|
579
|
+
pip install "code-review-graph[google-embeddings]" # Google Gemini embeddings
|
|
580
|
+
pip install "code-review-graph[communities]" # Community detection (igraph)
|
|
581
|
+
pip install "code-review-graph[enrichment]" # Python call-resolution enrichment (Jedi)
|
|
582
|
+
pip install "code-review-graph[eval]" # Evaluation benchmarks (matplotlib)
|
|
583
|
+
pip install "code-review-graph[wiki]" # Wiki generation with LLM summaries (ollama)
|
|
584
|
+
pip install "code-review-graph[all]" # All optional dependencies
|
|
553
585
|
```
|
|
554
586
|
|
|
555
587
|
### Environment Variables
|
|
@@ -604,12 +636,14 @@ The cloud-egress warning is auto-skipped when the base URL points to localhost
|
|
|
604
636
|
> `gemini-embedding-001` (via the native Gemini provider, which requires
|
|
605
637
|
> `GOOGLE_API_KEY` instead of the OpenAI-compatible path).
|
|
606
638
|
>
|
|
607
|
-
>
|
|
608
|
-
>
|
|
609
|
-
>
|
|
610
|
-
>
|
|
611
|
-
>
|
|
612
|
-
>
|
|
639
|
+
> `code-review-graph` embeds identifiers, signatures, structural context, and a
|
|
640
|
+
> bounded first-paragraph docstring/doc-comment summary. It does not transmit
|
|
641
|
+
> function bodies. Graphs created before documentation extraction was added
|
|
642
|
+
> need one full `code-review-graph build` before re-embedding so every file is
|
|
643
|
+
> reparsed. Routine builds never refresh embeddings by default. To refresh an
|
|
644
|
+
> existing index after a build, explicitly pass both `--embedding-provider`
|
|
645
|
+
> and `--embedding-model`; cloud choices may transmit this source-derived text
|
|
646
|
+
> and incur API cost.
|
|
613
647
|
|
|
614
648
|
#### Tool Filtering
|
|
615
649
|
|
|
@@ -714,5 +748,5 @@ MIT. See [LICENSE](LICENSE).
|
|
|
714
748
|
<br>
|
|
715
749
|
<a href="https://code-review-graph.com">code-review-graph.com</a><br><br>
|
|
716
750
|
<code>pip install code-review-graph && code-review-graph install</code><br>
|
|
717
|
-
<sub>Works with Codex, Claude Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, GitHub Copilot, and GitHub Copilot CLI</sub>
|
|
751
|
+
<sub>Works with Codex, Claude Code, CodeBuddy Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, GitHub Copilot, and GitHub Copilot CLI</sub>
|
|
718
752
|
</p>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<h1 align="center">code-review-graph</h1>
|
|
2
2
|
|
|
3
|
+
<a href="https://trendshift.io/repositories/23329?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-23329" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/23329" alt="tirth8205%2Fcode-review-graph | Trendshift" width="250" height="55"/></a>
|
|
4
|
+
|
|
3
5
|
<p align="center">
|
|
4
6
|
<strong>Stop burning tokens. Start reviewing smarter.</strong>
|
|
5
7
|
</p>
|
|
@@ -61,7 +63,7 @@ code-review-graph build # parse your codebase
|
|
|
61
63
|
One command sets up everything. `install` detects which AI coding tools you have, writes the correct MCP configuration for each one, installs platform-native hooks/skills where supported, and injects graph-aware instructions into your platform rules. It auto-detects whether you installed via `uvx` or `pip`/`pipx` and generates the right config. Restart your editor/tool after installing.
|
|
62
64
|
|
|
63
65
|
<p align="center">
|
|
64
|
-
<img src="diagrams/diagram8_supported_platforms.png" alt="One Install, Every Platform: auto-detects Codex, Claude Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, and GitHub Copilot" width="85%" />
|
|
66
|
+
<img src="diagrams/diagram8_supported_platforms.png" alt="One Install, Every Platform: auto-detects Codex, Claude Code, CodeBuddy Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, and GitHub Copilot" width="85%" />
|
|
65
67
|
</p>
|
|
66
68
|
|
|
67
69
|
To target a specific platform:
|
|
@@ -74,10 +76,27 @@ code-review-graph install --platform gemini-cli # configure only Gemini CLI
|
|
|
74
76
|
code-review-graph install --platform kiro # configure only Kiro
|
|
75
77
|
code-review-graph install --platform copilot # configure only GitHub Copilot (VS Code)
|
|
76
78
|
code-review-graph install --platform copilot-cli # configure only GitHub Copilot CLI
|
|
79
|
+
code-review-graph install --platform codebuddy # configure only CodeBuddy Code
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
Requires Python 3.10+. For the best experience, install [uv](https://docs.astral.sh/uv/) (the MCP config will use `uvx` if available, otherwise falls back to the `code-review-graph` command directly).
|
|
80
83
|
|
|
84
|
+
To remove CRG from a Git or SVN project, use the symmetric uninstall command
|
|
85
|
+
from anywhere inside its working tree. The target is normalized to the working
|
|
86
|
+
tree root, and non-repository directories are refused. It removes only
|
|
87
|
+
CRG-owned files and entries; unrelated MCP servers, hooks, skills, and JSONC
|
|
88
|
+
comments remain untouched. Shared configuration changes use atomic replacement
|
|
89
|
+
so a failed write leaves the original file intact.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
code-review-graph uninstall --dry-run # preview every action; write nothing
|
|
93
|
+
code-review-graph uninstall # preview, ask for confirmation, then apply
|
|
94
|
+
code-review-graph uninstall --yes # apply without prompting
|
|
95
|
+
code-review-graph uninstall --all-repos # also clean every registered repository
|
|
96
|
+
code-review-graph uninstall --keep-data # remove integrations but keep graph databases
|
|
97
|
+
code-review-graph uninstall --keep-user-configs --repo . # clean this project only
|
|
98
|
+
```
|
|
99
|
+
|
|
81
100
|
Then open your project and ask your AI assistant:
|
|
82
101
|
|
|
83
102
|
```
|
|
@@ -129,7 +148,12 @@ Large monorepos are where token waste is most painful. The graph cuts through th
|
|
|
129
148
|
<img src="diagrams/diagram9_language_coverage.png" alt="Language coverage organized by category: Web, Backend, Systems, Mobile, Scripting, Config, plus Jupyter and Databricks notebook support" width="90%" />
|
|
130
149
|
</p>
|
|
131
150
|
|
|
132
|
-
Parser support covers functions, classes, imports, call sites, inheritance, and test detection across the current parser surface, using Tree-sitter where available and targeted fallbacks where needed. Current support includes Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL,
|
|
151
|
+
Parser support covers functions, classes, imports, call sites, inheritance, and test detection across the current parser surface, using Tree-sitter where available and targeted fallbacks where needed. Current support includes Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, VB.NET, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL, Terraform/OpenTofu structure (`.tf`; generic `.hcl` files are recognized as file nodes), Ansible playbooks/roles/tasks, Vue/Svelte SFCs, Astro files parsed through the TypeScript parser, Jupyter/Databricks notebooks (`.ipynb`), and Perl XS files (`.xs`). Generic YAML is not treated as source code.
|
|
152
|
+
|
|
153
|
+
PHP projects additionally get repository-bounded Composer PSR-4 resolution,
|
|
154
|
+
Blade template references, and Laravel Route/Eloquent semantic edges when the
|
|
155
|
+
source includes explicit framework imports, model inheritance, and receiver
|
|
156
|
+
evidence.
|
|
133
157
|
|
|
134
158
|
### Add your own language (no fork needed)
|
|
135
159
|
|
|
@@ -164,7 +188,7 @@ jobs:
|
|
|
164
188
|
review:
|
|
165
189
|
runs-on: ubuntu-latest
|
|
166
190
|
steps:
|
|
167
|
-
- uses: actions/checkout@
|
|
191
|
+
- uses: actions/checkout@v7
|
|
168
192
|
- uses: tirth8205/code-review-graph@v2.3.6
|
|
169
193
|
with:
|
|
170
194
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -248,7 +272,7 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
248
272
|
- **Impact "recall 1.0" is graph-derived and circular:** the historical ground truth comes from the same graph edges the predictor walks, so it is an upper bound by construction. The honest co-change mode (grade against files actually co-changed in the same commit) is measured alongside it; expect those numbers to be substantially lower.
|
|
249
273
|
- **Small single-file changes:** Graph context can exceed naive file reads for trivial edits (see express results above). The overhead is the structural metadata that enables multi-file analysis.
|
|
250
274
|
- **Search quality (MRR 0.35):** Keyword search finds the right result in the top-4 for most queries, but ranking needs improvement. Express queries return 0 hits due to module-pattern naming.
|
|
251
|
-
- **Flow detection (33% recall):**
|
|
275
|
+
- **Flow detection (33% recall):** Framework and conventional entry patterns are strongest for Python and PHP/Laravel. JavaScript and Go flow detection needs work.
|
|
252
276
|
- **Precision vs recall trade-off:** Impact analysis is deliberately conservative. It flags files that *might* be affected, which means some false positives in large dependency graphs.
|
|
253
277
|
|
|
254
278
|
---
|
|
@@ -258,7 +282,8 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
258
282
|
| Feature | Details |
|
|
259
283
|
|---------|---------|
|
|
260
284
|
| **Incremental updates** | Re-parses only changed files. Subsequent updates complete in under 2 seconds. |
|
|
261
|
-
| **Broad language + notebook support** | Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL,
|
|
285
|
+
| **Broad language + notebook support** | Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, VB.NET, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL, Terraform/OpenTofu structure (`.tf`; generic `.hcl` files are file-only), Ansible playbooks/roles/tasks, Vue/Svelte SFCs, Astro files parsed through the TypeScript parser, Jupyter/Databricks (.ipynb), and Perl XS (.xs) |
|
|
286
|
+
| **Framework-aware PHP parsing** | Repository-bounded Composer PSR-4 imports, Blade template references, and evidence-gated Laravel Route-to-controller and Eloquent relationship edges |
|
|
262
287
|
| **Blast-radius analysis** | Shows which functions, classes, and files are likely affected by a change |
|
|
263
288
|
| **Auto-update hooks** | Hooks and watch mode can update the graph on file saves and supported commit hooks |
|
|
264
289
|
| **Semantic search** | Optional vector embeddings via sentence-transformers, Google Gemini, MiniMax, or any OpenAI-compatible endpoint (real OpenAI, Azure, new-api, LiteLLM, vLLM, LocalAI) |
|
|
@@ -313,11 +338,13 @@ The benchmark also runs an honest **co-change mode**: the predictor is seeded wi
|
|
|
313
338
|
```bash
|
|
314
339
|
code-review-graph install # Auto-detect and configure all platforms
|
|
315
340
|
code-review-graph install --platform <name> # Target a specific platform
|
|
341
|
+
code-review-graph uninstall --dry-run # Preview safe removal of installed artifacts
|
|
316
342
|
code-review-graph build # Parse entire codebase
|
|
317
343
|
code-review-graph update # Incremental update (changed files only)
|
|
318
344
|
code-review-graph status # Graph statistics
|
|
319
345
|
code-review-graph watch # Auto-update on file changes
|
|
320
346
|
code-review-graph visualize # Generate interactive HTML graph
|
|
347
|
+
code-review-graph visualize --format json # Export local graph data as JSON
|
|
321
348
|
code-review-graph visualize --format graphml # Export as GraphML
|
|
322
349
|
code-review-graph visualize --format svg # Export as SVG
|
|
323
350
|
code-review-graph visualize --format obsidian # Export as Obsidian vault
|
|
@@ -336,6 +363,10 @@ code-review-graph eval # Run evaluation benchmarks
|
|
|
336
363
|
code-review-graph serve # Start MCP server
|
|
337
364
|
```
|
|
338
365
|
|
|
366
|
+
JSON exports stay inside the local graph data directory, which Git ignores by
|
|
367
|
+
default. They can contain absolute paths and code-structure metadata, so inspect
|
|
368
|
+
and sanitize an export before publishing it outside your machine.
|
|
369
|
+
|
|
339
370
|
</details>
|
|
340
371
|
|
|
341
372
|
<details>
|
|
@@ -481,13 +512,13 @@ Note: in git repos, only tracked files are indexed (`git ls-files`), so gitignor
|
|
|
481
512
|
Optional dependency groups:
|
|
482
513
|
|
|
483
514
|
```bash
|
|
484
|
-
pip install code-review-graph[embeddings] # Local vector embeddings (sentence-transformers)
|
|
485
|
-
pip install code-review-graph[google-embeddings] # Google Gemini embeddings
|
|
486
|
-
pip install code-review-graph[communities] # Community detection (igraph)
|
|
487
|
-
pip install code-review-graph[enrichment] # Python call-resolution enrichment (Jedi)
|
|
488
|
-
pip install code-review-graph[eval] # Evaluation benchmarks (matplotlib)
|
|
489
|
-
pip install code-review-graph[wiki] # Wiki generation with LLM summaries (ollama)
|
|
490
|
-
pip install code-review-graph[all] # All optional dependencies
|
|
515
|
+
pip install "code-review-graph[embeddings]" # Local vector embeddings (sentence-transformers)
|
|
516
|
+
pip install "code-review-graph[google-embeddings]" # Google Gemini embeddings
|
|
517
|
+
pip install "code-review-graph[communities]" # Community detection (igraph)
|
|
518
|
+
pip install "code-review-graph[enrichment]" # Python call-resolution enrichment (Jedi)
|
|
519
|
+
pip install "code-review-graph[eval]" # Evaluation benchmarks (matplotlib)
|
|
520
|
+
pip install "code-review-graph[wiki]" # Wiki generation with LLM summaries (ollama)
|
|
521
|
+
pip install "code-review-graph[all]" # All optional dependencies
|
|
491
522
|
```
|
|
492
523
|
|
|
493
524
|
### Environment Variables
|
|
@@ -542,12 +573,14 @@ The cloud-egress warning is auto-skipped when the base URL points to localhost
|
|
|
542
573
|
> `gemini-embedding-001` (via the native Gemini provider, which requires
|
|
543
574
|
> `GOOGLE_API_KEY` instead of the OpenAI-compatible path).
|
|
544
575
|
>
|
|
545
|
-
>
|
|
546
|
-
>
|
|
547
|
-
>
|
|
548
|
-
>
|
|
549
|
-
>
|
|
550
|
-
>
|
|
576
|
+
> `code-review-graph` embeds identifiers, signatures, structural context, and a
|
|
577
|
+
> bounded first-paragraph docstring/doc-comment summary. It does not transmit
|
|
578
|
+
> function bodies. Graphs created before documentation extraction was added
|
|
579
|
+
> need one full `code-review-graph build` before re-embedding so every file is
|
|
580
|
+
> reparsed. Routine builds never refresh embeddings by default. To refresh an
|
|
581
|
+
> existing index after a build, explicitly pass both `--embedding-provider`
|
|
582
|
+
> and `--embedding-model`; cloud choices may transmit this source-derived text
|
|
583
|
+
> and incur API cost.
|
|
551
584
|
|
|
552
585
|
#### Tool Filtering
|
|
553
586
|
|
|
@@ -652,5 +685,5 @@ MIT. See [LICENSE](LICENSE).
|
|
|
652
685
|
<br>
|
|
653
686
|
<a href="https://code-review-graph.com">code-review-graph.com</a><br><br>
|
|
654
687
|
<code>pip install code-review-graph && code-review-graph install</code><br>
|
|
655
|
-
<sub>Works with Codex, Claude Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, GitHub Copilot, and GitHub Copilot CLI</sub>
|
|
688
|
+
<sub>Works with Codex, Claude Code, CodeBuddy Code, Cursor, Windsurf, Zed, Continue, OpenCode, Antigravity, Gemini CLI, Qwen, Qoder, Kiro, GitHub Copilot, and GitHub Copilot CLI</sub>
|
|
656
689
|
</p>
|
|
@@ -167,7 +167,100 @@ def _parse_unified_diff(diff_text: str) -> dict[str, list[tuple[int, int]]]:
|
|
|
167
167
|
|
|
168
168
|
|
|
169
169
|
# ---------------------------------------------------------------------------
|
|
170
|
-
# 2.
|
|
170
|
+
# 2. compute_file_churn
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
_CHURN_SATURATION = 10.0
|
|
174
|
+
_CHURN_WEIGHT = 0.15
|
|
175
|
+
_NUMSTAT_COUNT = re.compile(r"^(?:\d+|-)$")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _parse_numstat(log_text: str) -> dict[str, int]:
|
|
179
|
+
"""Parse NUL-terminated ``git log --numstat -z`` records.
|
|
180
|
+
|
|
181
|
+
NUL termination is required for correctness: Git's default line format
|
|
182
|
+
quotes unusual paths, while ``-z`` preserves tabs and newlines in file
|
|
183
|
+
names without making the graph-path lookup ambiguous.
|
|
184
|
+
"""
|
|
185
|
+
counts: dict[str, int] = {}
|
|
186
|
+
for record in log_text.split("\0"):
|
|
187
|
+
if not record:
|
|
188
|
+
continue
|
|
189
|
+
fields = record.split("\t", 2)
|
|
190
|
+
if len(fields) != 3:
|
|
191
|
+
continue
|
|
192
|
+
added, deleted, path = fields
|
|
193
|
+
if (
|
|
194
|
+
not path
|
|
195
|
+
or _NUMSTAT_COUNT.fullmatch(added) is None
|
|
196
|
+
or _NUMSTAT_COUNT.fullmatch(deleted) is None
|
|
197
|
+
):
|
|
198
|
+
continue
|
|
199
|
+
counts[path] = counts.get(path, 0) + 1
|
|
200
|
+
return counts
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def compute_file_churn(
|
|
204
|
+
repo_root: str,
|
|
205
|
+
window_days: int | None = None,
|
|
206
|
+
) -> dict[str, int]:
|
|
207
|
+
"""Count commits touching each file over a trailing window.
|
|
208
|
+
|
|
209
|
+
Returns an empty mapping when the window is invalid or Git cannot be
|
|
210
|
+
queried. Renames are deliberately not followed: churn belongs to the path
|
|
211
|
+
that existed in each commit.
|
|
212
|
+
"""
|
|
213
|
+
if window_days is None:
|
|
214
|
+
raw_window = os.environ.get("CRG_CHURN_WINDOW_DAYS", "90")
|
|
215
|
+
try:
|
|
216
|
+
window_days = int(raw_window)
|
|
217
|
+
except ValueError:
|
|
218
|
+
logger.warning(
|
|
219
|
+
"Invalid CRG_CHURN_WINDOW_DAYS value %r; churn disabled",
|
|
220
|
+
raw_window,
|
|
221
|
+
)
|
|
222
|
+
return {}
|
|
223
|
+
if window_days <= 0:
|
|
224
|
+
return {}
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
result = subprocess.run(
|
|
228
|
+
[
|
|
229
|
+
"git",
|
|
230
|
+
"-c",
|
|
231
|
+
"core.quotepath=off",
|
|
232
|
+
"log",
|
|
233
|
+
f"--since={window_days}.days.ago",
|
|
234
|
+
"--numstat",
|
|
235
|
+
"--no-renames",
|
|
236
|
+
"--format=",
|
|
237
|
+
"-z",
|
|
238
|
+
"--",
|
|
239
|
+
],
|
|
240
|
+
capture_output=True,
|
|
241
|
+
stdin=subprocess.DEVNULL,
|
|
242
|
+
text=True,
|
|
243
|
+
encoding="utf-8",
|
|
244
|
+
errors="replace",
|
|
245
|
+
cwd=repo_root,
|
|
246
|
+
timeout=_GIT_TIMEOUT,
|
|
247
|
+
)
|
|
248
|
+
if result.returncode != 0:
|
|
249
|
+
logger.warning(
|
|
250
|
+
"git log failed (rc=%d): %s",
|
|
251
|
+
result.returncode,
|
|
252
|
+
result.stderr[:200],
|
|
253
|
+
)
|
|
254
|
+
return {}
|
|
255
|
+
except (OSError, subprocess.SubprocessError) as exc:
|
|
256
|
+
logger.warning("git log error: %s", exc)
|
|
257
|
+
return {}
|
|
258
|
+
|
|
259
|
+
return _parse_numstat(result.stdout)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
# 3. map_changes_to_nodes
|
|
171
264
|
# ---------------------------------------------------------------------------
|
|
172
265
|
|
|
173
266
|
|
|
@@ -212,11 +305,15 @@ def map_changes_to_nodes(
|
|
|
212
305
|
|
|
213
306
|
|
|
214
307
|
# ---------------------------------------------------------------------------
|
|
215
|
-
#
|
|
308
|
+
# 4. compute_risk_score
|
|
216
309
|
# ---------------------------------------------------------------------------
|
|
217
310
|
|
|
218
311
|
|
|
219
|
-
def compute_risk_score(
|
|
312
|
+
def compute_risk_score(
|
|
313
|
+
store: GraphStore,
|
|
314
|
+
node: GraphNode,
|
|
315
|
+
churn_counts: dict[str, int] | None = None,
|
|
316
|
+
) -> float:
|
|
220
317
|
"""Compute a risk score (0.0 - 1.0) for a single node.
|
|
221
318
|
|
|
222
319
|
Scoring factors:
|
|
@@ -225,6 +322,8 @@ def compute_risk_score(store: GraphStore, node: GraphNode) -> float:
|
|
|
225
322
|
- Test coverage: 0.30 (untested) scaling down to 0.05 (5+ TESTED_BY edges)
|
|
226
323
|
- Security sensitivity: 0.20 if name matches security keywords
|
|
227
324
|
- Caller count: callers / 20, capped at 0.10
|
|
325
|
+
- Change frequency (opt-in): commits touching the file / 10, capped
|
|
326
|
+
at 0.15
|
|
228
327
|
"""
|
|
229
328
|
score = 0.0
|
|
230
329
|
|
|
@@ -266,11 +365,16 @@ def compute_risk_score(store: GraphStore, node: GraphNode) -> float:
|
|
|
266
365
|
caller_count = len(caller_edges)
|
|
267
366
|
score += min(caller_count / 20.0, 0.10)
|
|
268
367
|
|
|
368
|
+
# --- Change frequency (opt-in, cap 0.15) ---
|
|
369
|
+
if churn_counts and node.file_path:
|
|
370
|
+
commit_count = churn_counts.get(node.file_path, 0)
|
|
371
|
+
score += min(commit_count / _CHURN_SATURATION, 1.0) * _CHURN_WEIGHT
|
|
372
|
+
|
|
269
373
|
return round(min(max(score, 0.0), 1.0), 4)
|
|
270
374
|
|
|
271
375
|
|
|
272
376
|
# ---------------------------------------------------------------------------
|
|
273
|
-
#
|
|
377
|
+
# 5. analyze_changes
|
|
274
378
|
# ---------------------------------------------------------------------------
|
|
275
379
|
|
|
276
380
|
|
|
@@ -280,6 +384,7 @@ def analyze_changes(
|
|
|
280
384
|
changed_ranges: dict[str, list[tuple[int, int]]] | None = None,
|
|
281
385
|
repo_root: str | None = None,
|
|
282
386
|
base: str = "HEAD~1",
|
|
387
|
+
include_churn: bool = False,
|
|
283
388
|
) -> dict[str, Any]:
|
|
284
389
|
"""Analyze changes and produce risk-scored review guidance.
|
|
285
390
|
|
|
@@ -291,6 +396,9 @@ def analyze_changes(
|
|
|
291
396
|
(Git or SVN).
|
|
292
397
|
repo_root: Repository root (for git/svn diff).
|
|
293
398
|
base: Git ref or SVN revision range to diff against.
|
|
399
|
+
include_churn: Add an opt-in change-frequency term to each node's
|
|
400
|
+
risk score. The trailing window defaults to 90 days and can be
|
|
401
|
+
configured with ``CRG_CHURN_WINDOW_DAYS``.
|
|
294
402
|
|
|
295
403
|
Returns:
|
|
296
404
|
Dict with ``summary``, ``risk_score``, ``changed_functions``,
|
|
@@ -320,10 +428,12 @@ def analyze_changes(
|
|
|
320
428
|
for fp in changed_files:
|
|
321
429
|
changed_nodes.extend(store.get_nodes_by_file(fp))
|
|
322
430
|
|
|
323
|
-
#
|
|
431
|
+
# RTL declarations are stored as Function nodes for compatibility but
|
|
432
|
+
# are not callable/testable functions.
|
|
324
433
|
changed_funcs = [
|
|
325
434
|
n for n in changed_nodes
|
|
326
435
|
if n.kind in ("Function", "Test", "Class")
|
|
436
|
+
and not n.extra.get("verilog_kind")
|
|
327
437
|
]
|
|
328
438
|
|
|
329
439
|
# Cap to prevent O(N*M) query explosion on large PRs.
|
|
@@ -332,10 +442,18 @@ def analyze_changes(
|
|
|
332
442
|
if funcs_truncated:
|
|
333
443
|
changed_funcs = changed_funcs[:_max_funcs]
|
|
334
444
|
|
|
445
|
+
churn_counts: dict[str, int] | None = None
|
|
446
|
+
if include_churn and repo_root is not None:
|
|
447
|
+
churn_counts = {}
|
|
448
|
+
root_path = Path(repo_root)
|
|
449
|
+
for key, count in compute_file_churn(repo_root).items():
|
|
450
|
+
churn_counts[key] = count
|
|
451
|
+
churn_counts[str(root_path / key)] = count
|
|
452
|
+
|
|
335
453
|
# Compute per-node risk scores.
|
|
336
454
|
node_risks: list[dict[str, Any]] = []
|
|
337
455
|
for node in changed_funcs:
|
|
338
|
-
risk = compute_risk_score(store, node)
|
|
456
|
+
risk = compute_risk_score(store, node, churn_counts)
|
|
339
457
|
node_risks.append({
|
|
340
458
|
**node_to_dict(node),
|
|
341
459
|
"risk_score": risk,
|
|
@@ -352,7 +470,10 @@ def analyze_changes(
|
|
|
352
470
|
for node in changed_funcs:
|
|
353
471
|
if node.is_test:
|
|
354
472
|
continue
|
|
355
|
-
|
|
473
|
+
# TESTED_BY edges are stored as source=production, target=test by the
|
|
474
|
+
# parser, so a changed production function finds its tests by source.
|
|
475
|
+
# See: #515
|
|
476
|
+
tested = store.get_edges_by_source(node.qualified_name)
|
|
356
477
|
if not any(e.kind == "TESTED_BY" for e in tested):
|
|
357
478
|
test_gaps.append({
|
|
358
479
|
"name": _sanitize_name(node.name),
|