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.
Files changed (112) hide show
  1. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/PKG-INFO +58 -24
  2. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/README.md +52 -19
  3. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/__init__.py +1 -1
  4. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/changes.py +128 -7
  5. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/cli.py +592 -61
  6. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/communities.py +235 -21
  7. code_review_graph_codeblackwell-3.0.0/code_review_graph/config_keys.py +33 -0
  8. code_review_graph_codeblackwell-3.0.0/code_review_graph/constants.py +73 -0
  9. code_review_graph_codeblackwell-3.0.0/code_review_graph/css_resolver.py +155 -0
  10. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/daemon.py +67 -6
  11. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/daemon_cli.py +12 -3
  12. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/embeddings.py +157 -23
  13. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/enrich.py +8 -5
  14. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/fastapi.yaml +7 -7
  15. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/runner.py +16 -2
  16. code_review_graph_codeblackwell-3.0.0/code_review_graph/event_resolver.py +122 -0
  17. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/exports.py +39 -1
  18. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/flows.py +16 -0
  19. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/graph.py +567 -243
  20. code_review_graph_codeblackwell-3.0.0/code_review_graph/hcl_resolver.py +110 -0
  21. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/incremental.py +197 -309
  22. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/main.py +183 -119
  23. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/migrations.py +13 -0
  24. code_review_graph_codeblackwell-3.0.0/code_review_graph/parser.py +14878 -0
  25. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/postprocessing.py +72 -6
  26. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/refactor.py +32 -7
  27. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/search.py +19 -0
  28. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/skills.py +289 -57
  29. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/__init__.py +2 -0
  30. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/_common.py +115 -0
  31. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/build.py +131 -0
  32. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/docs.py +3 -2
  33. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/query.py +289 -91
  34. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/review.py +0 -8
  35. code_review_graph_codeblackwell-3.0.0/code_review_graph/uninstall.py +1265 -0
  36. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/visualization.py +76 -45
  37. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/COMMANDS.md +5 -4
  38. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/FAQ.md +1 -1
  39. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/FEATURES.md +2 -1
  40. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/GITHUB_ACTION.md +34 -10
  41. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/LLM-OPTIMIZED-REFERENCE.md +2 -2
  42. code_review_graph_codeblackwell-3.0.0/docs/MAINTAINER_RECONCILIATION_2026-07-17.md +291 -0
  43. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/TROUBLESHOOTING.md +10 -10
  44. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/USAGE.md +27 -2
  45. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/architecture.md +1 -1
  46. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/schema.md +11 -23
  47. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/pyproject.toml +6 -5
  48. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/debug-issue/SKILL.md +1 -1
  49. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/explore-codebase/SKILL.md +1 -1
  50. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/refactor-safely/SKILL.md +1 -1
  51. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/review-changes/SKILL.md +1 -1
  52. code_review_graph_codeblackwell-2.4.0/code_review_graph/constants.py +0 -23
  53. code_review_graph_codeblackwell-2.4.0/code_review_graph/parser.py +0 -8058
  54. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/README.md +0 -0
  55. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/post-checkout +0 -0
  56. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/post-merge +0 -0
  57. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/pre-commit +0 -0
  58. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/pre-push +0 -0
  59. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.beads/hooks/prepare-commit-msg +0 -0
  60. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/.gitignore +0 -0
  61. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/LICENSE +0 -0
  62. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code-review-graph-vscode/LICENSE +0 -0
  63. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code-review-graph-vscode/README.md +0 -0
  64. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/__main__.py +0 -0
  65. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/analysis.py +0 -0
  66. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/context_savings.py +0 -0
  67. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/custom_languages.py +0 -0
  68. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/__init__.py +0 -0
  69. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/__init__.py +0 -0
  70. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/agent_baseline.py +0 -0
  71. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/build_performance.py +0 -0
  72. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/flow_completeness.py +0 -0
  73. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/impact_accuracy.py +0 -0
  74. {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
  75. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/search_quality.py +0 -0
  76. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/benchmarks/token_efficiency.py +0 -0
  77. {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
  78. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/express.yaml +0 -0
  79. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/flask.yaml +0 -0
  80. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/gin.yaml +0 -0
  81. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/configs/httpx.yaml +0 -0
  82. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/reporter.py +0 -0
  83. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/scorer.py +0 -0
  84. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/eval/token_benchmark.py +0 -0
  85. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/graph_diff.py +0 -0
  86. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/hints.py +0 -0
  87. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/jedi_resolver.py +0 -0
  88. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/memory.py +0 -0
  89. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/prompts.py +0 -0
  90. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/registry.py +0 -0
  91. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/rescript_resolver.py +0 -0
  92. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/spring_resolver.py +0 -0
  93. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/temporal_resolver.py +0 -0
  94. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/token_benchmark.py +0 -0
  95. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/analysis_tools.py +0 -0
  96. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/community_tools.py +0 -0
  97. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/context.py +0 -0
  98. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/flows_tools.py +0 -0
  99. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/refactor_tools.py +0 -0
  100. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tools/registry_tools.py +0 -0
  101. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/tsconfig_resolver.py +0 -0
  102. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/code_review_graph/wiki.py +0 -0
  103. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/CUSTOM_LANGUAGES.md +0 -0
  104. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/INDEX.md +0 -0
  105. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/LEGAL.md +0 -0
  106. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/REPRODUCING.md +0 -0
  107. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/docs/ROADMAP.md +0 -0
  108. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/hooks/hooks.json +0 -0
  109. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/hooks/session-start.sh +0 -0
  110. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/build-graph/SKILL.md +0 -0
  111. {code_review_graph_codeblackwell-2.4.0 → code_review_graph_codeblackwell-3.0.0}/skills/review-delta/SKILL.md +0 -0
  112. {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: 2.4.0
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<6,>=4.0.0
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<4,>=3.0.0; extra == 'all'
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<1,>=0.23; extra == 'dev'
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<4,>=3.0.0; extra == 'embeddings'
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&amp;utm_medium=badge&amp;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, CSS/SCSS/LESS stylesheets, Vue/Svelte SFCs (including `<style>` blocks), Astro files parsed through the TypeScript parser, Jupyter/Databricks notebooks (`.ipynb`), and Perl XS files (`.xs`).
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@v4
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):** Only reliably detects entry points in Python repos (fastapi, httpx) where framework patterns are recognized. JavaScript and Go flow detection needs work.
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, CSS/SCSS/LESS, Vue/Svelte SFCs (including `<style>` blocks), Astro files parsed through the TypeScript parser, Jupyter/Databricks (.ipynb), and Perl XS (.xs) |
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
- > Also note: `code-review-graph` currently embeds **function signatures only**
608
- > (~10 tokens per node, e.g. `"parse_file function (path: str) returns Tree"`).
609
- > Models whose headline quality comes from long-context body understanding
610
- > (such as Gemini 2 or Qwen3-8B at their MTEB-code SOTA scores) will see a
611
- > much narrower quality gap against smaller models at this input length.
612
- > Body/docstring embedding is tracked as a follow-up enhancement.
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&amp;utm_medium=badge&amp;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, CSS/SCSS/LESS stylesheets, Vue/Svelte SFCs (including `<style>` blocks), Astro files parsed through the TypeScript parser, Jupyter/Databricks notebooks (`.ipynb`), and Perl XS files (`.xs`).
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@v4
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):** Only reliably detects entry points in Python repos (fastapi, httpx) where framework patterns are recognized. JavaScript and Go flow detection needs work.
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, CSS/SCSS/LESS, Vue/Svelte SFCs (including `<style>` blocks), Astro files parsed through the TypeScript parser, Jupyter/Databricks (.ipynb), and Perl XS (.xs) |
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
- > Also note: `code-review-graph` currently embeds **function signatures only**
546
- > (~10 tokens per node, e.g. `"parse_file function (path: str) returns Tree"`).
547
- > Models whose headline quality comes from long-context body understanding
548
- > (such as Gemini 2 or Qwen3-8B at their MTEB-code SOTA scores) will see a
549
- > much narrower quality gap against smaller models at this input length.
550
- > Body/docstring embedding is tracked as a follow-up enhancement.
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>
@@ -8,7 +8,7 @@ from .context_savings import (
8
8
  format_context_savings,
9
9
  )
10
10
 
11
- __version__ = "2.3.6"
11
+ __version__ = "3.0.0"
12
12
 
13
13
  __all__ = [
14
14
  "__version__",
@@ -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. map_changes_to_nodes
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
- # 3. compute_risk_score
308
+ # 4. compute_risk_score
216
309
  # ---------------------------------------------------------------------------
217
310
 
218
311
 
219
- def compute_risk_score(store: GraphStore, node: GraphNode) -> float:
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
- # 4. analyze_changes
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
- # Filter to functions/tests for risk scoring (skip File nodes).
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
- tested = store.get_edges_by_target(node.qualified_name)
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),