code-review-ai-cli 1.2.0__tar.gz → 1.3.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 (29) hide show
  1. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/PKG-INFO +91 -2
  2. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/README.md +90 -1
  3. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/PKG-INFO +91 -2
  4. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/SOURCES.txt +2 -0
  5. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/pyproject.toml +1 -1
  6. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/ai_review.py +65 -25
  7. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/config.py +11 -3
  8. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/git_utils.py +112 -2
  9. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/llm_client.py +0 -18
  10. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/prompts/config.yaml.template +10 -3
  11. code_review_ai_cli-1.3.0/src/rag_engine.py +162 -0
  12. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/tfs_client.py +28 -134
  13. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_ai_review.py +17 -7
  14. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_config.py +2 -2
  15. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_git_utils.py +153 -1
  16. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_llm_client.py +0 -1
  17. code_review_ai_cli-1.3.0/tests/test_rag_engine.py +250 -0
  18. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_tfs_client.py +66 -87
  19. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/dependency_links.txt +0 -0
  20. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/entry_points.txt +0 -0
  21. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/requires.txt +0 -0
  22. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/code_review_ai_cli.egg-info/top_level.txt +0 -0
  23. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/setup.cfg +0 -0
  24. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/__init__.py +0 -0
  25. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/formatter.py +0 -0
  26. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/prompts/review_context.example.md +0 -0
  27. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/src/usage_tracker.py +0 -0
  28. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_formatter.py +0 -0
  29. {code_review_ai_cli-1.2.0 → code_review_ai_cli-1.3.0}/tests/test_usage_tracker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-review-ai-cli
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
5
5
  License: MIT
6
6
  Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
@@ -48,10 +48,48 @@ Automated code review tool with Pull Request integration for Azure DevOps/TFS an
48
48
  - **Multiple LLM Providers** — OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
49
49
  - **Smart Filtering** — Filter by file extensions, limit diff size
50
50
  - **Project-aware PR Context** — Sends repository and linked work item context while restricting findings to modified PR lines
51
+ - **RAG Context** — Enriches the review with related code snippets found via `git grep` in the local repository
51
52
  - **Single Reviewer Context** — One Markdown context file with local override support
52
53
  - **Usage Tracking** — Store per-PR token usage and optional cost estimates
53
54
  - **Interactive CLI** — Menu-driven selection and confirmation
54
55
 
56
+ ## Local Repository Requirement
57
+
58
+ > **The CLI must be run from inside the local clone of the repository being reviewed.**
59
+
60
+ The PR diff is fetched from Azure DevOps/TFS, but several features depend on the local git state:
61
+
62
+ | Feature | Local dependency |
63
+ |---|---|
64
+ | PR diff | `git fetch` + three-dot diff against `origin/<branch>` |
65
+ | RAG context | `git grep` on the working tree |
66
+ | Branch validation | `git branch --show-current` |
67
+
68
+ ### Branch requirement when RAG is enabled
69
+
70
+ When `review.rag.enabled: true`, the local repository **must be checked out on the PR target branch** (e.g. `development`). If the local branch differs from the target, the review is blocked:
71
+
72
+ ```
73
+ Local branch mismatch: you are on 'main' but this PR targets 'development'.
74
+ RAG context would be built from the wrong branch, which may corrupt the review.
75
+ Please run: git checkout development
76
+ ```
77
+
78
+ **Example:**
79
+ ```bash
80
+ # PR: merge 'feature/my-feature' → 'development'
81
+ cd /path/to/my-repo # must be inside the repo
82
+ git checkout development # must match PR target branch
83
+ ai-review pr-review 42
84
+ ```
85
+
86
+ To skip the branch check entirely, disable RAG:
87
+ ```yaml
88
+ review:
89
+ rag:
90
+ enabled: false
91
+ ```
92
+
55
93
  ## Installation & Quick Start
56
94
 
57
95
  ### 1. Install Package
@@ -129,11 +167,14 @@ tfs:
129
167
  review:
130
168
  language: pt
131
169
  verbosity: detailed # or: quick, security
132
- scope: diff_with_context # diff_with_context, diff_only, full_code
170
+ scope: diff_with_context # diff_with_context, diff_only
133
171
  file_extensions_filter: [".cs", ".ts", ".py"]
134
172
  max_diff_files: 50
135
173
  max_comments_to_post: 20
136
174
  custom_prompt_file: review_context.local.md
175
+ rag:
176
+ enabled: true # requires local branch == PR target
177
+ max_chars: 40000
137
178
  project_context:
138
179
  enabled: true
139
180
  mode: on_demand # on_demand, full
@@ -180,11 +221,59 @@ src/
180
221
  tfs_client.py # Azure DevOps integration
181
222
  git_utils.py # Git diff processing
182
223
  formatter.py # Output formatting (terminal, markdown, JSON)
224
+ rag_engine.py # RAG context via git grep
183
225
 
184
226
  tests/
185
227
  test_*.py # Unit and integration tests
186
228
  ```
187
229
 
230
+ ## RAG Context
231
+
232
+ ### Current Implementation
233
+
234
+ The RAG engine enriches the LLM prompt with related code snippets found in the local repository:
235
+
236
+ 1. **Extract identifiers** — function and class names are parsed from the PR diff
237
+ 2. **Search** — `git grep` finds files containing those identifiers
238
+ 3. **Extract snippets** — ±10 lines around each match are included as read-only context
239
+
240
+ All operations run locally with no extra dependencies. The quality of RAG context depends entirely on the local repository state, which is why the **local branch must match the PR target branch**.
241
+
242
+ ### Recommended Stack for Enhanced RAG (Local & Open Source)
243
+
244
+ For teams wanting semantic similarity instead of keyword search, the recommended local stack is:
245
+
246
+ | Component | Library | Reason |
247
+ |---|---|---|
248
+ | **Vector database** | [ChromaDB](https://www.trychroma.com/) | Runs in-memory or persists to a local SQLite file — no server needed, `pip install chromadb` |
249
+ | **Embeddings** | [sentence-transformers](https://www.sbert.net/) | Generates vectors locally on CPU — no API calls, no cost |
250
+
251
+ Example integration pattern:
252
+
253
+ ```python
254
+ from sentence_transformers import SentenceTransformer
255
+ import chromadb
256
+
257
+ model = SentenceTransformer("all-MiniLM-L6-v2") # ~80 MB, CPU-friendly
258
+ client = chromadb.Client() # in-memory
259
+ collection = client.create_collection("repo-index")
260
+
261
+ # Index
262
+ collection.add(
263
+ documents=[snippet_text],
264
+ embeddings=model.encode([snippet_text]).tolist(),
265
+ ids=["file:line"],
266
+ )
267
+
268
+ # Query
269
+ results = collection.query(
270
+ query_embeddings=model.encode([query]).tolist(),
271
+ n_results=5,
272
+ )
273
+ ```
274
+
275
+ This stack keeps the CLI lightweight (`pip install`) and requires no external services or paid APIs.
276
+
188
277
  ### Run Tests
189
278
 
190
279
  ```bash
@@ -11,10 +11,48 @@ Automated code review tool with Pull Request integration for Azure DevOps/TFS an
11
11
  - **Multiple LLM Providers** — OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
12
12
  - **Smart Filtering** — Filter by file extensions, limit diff size
13
13
  - **Project-aware PR Context** — Sends repository and linked work item context while restricting findings to modified PR lines
14
+ - **RAG Context** — Enriches the review with related code snippets found via `git grep` in the local repository
14
15
  - **Single Reviewer Context** — One Markdown context file with local override support
15
16
  - **Usage Tracking** — Store per-PR token usage and optional cost estimates
16
17
  - **Interactive CLI** — Menu-driven selection and confirmation
17
18
 
19
+ ## Local Repository Requirement
20
+
21
+ > **The CLI must be run from inside the local clone of the repository being reviewed.**
22
+
23
+ The PR diff is fetched from Azure DevOps/TFS, but several features depend on the local git state:
24
+
25
+ | Feature | Local dependency |
26
+ |---|---|
27
+ | PR diff | `git fetch` + three-dot diff against `origin/<branch>` |
28
+ | RAG context | `git grep` on the working tree |
29
+ | Branch validation | `git branch --show-current` |
30
+
31
+ ### Branch requirement when RAG is enabled
32
+
33
+ When `review.rag.enabled: true`, the local repository **must be checked out on the PR target branch** (e.g. `development`). If the local branch differs from the target, the review is blocked:
34
+
35
+ ```
36
+ Local branch mismatch: you are on 'main' but this PR targets 'development'.
37
+ RAG context would be built from the wrong branch, which may corrupt the review.
38
+ Please run: git checkout development
39
+ ```
40
+
41
+ **Example:**
42
+ ```bash
43
+ # PR: merge 'feature/my-feature' → 'development'
44
+ cd /path/to/my-repo # must be inside the repo
45
+ git checkout development # must match PR target branch
46
+ ai-review pr-review 42
47
+ ```
48
+
49
+ To skip the branch check entirely, disable RAG:
50
+ ```yaml
51
+ review:
52
+ rag:
53
+ enabled: false
54
+ ```
55
+
18
56
  ## Installation & Quick Start
19
57
 
20
58
  ### 1. Install Package
@@ -92,11 +130,14 @@ tfs:
92
130
  review:
93
131
  language: pt
94
132
  verbosity: detailed # or: quick, security
95
- scope: diff_with_context # diff_with_context, diff_only, full_code
133
+ scope: diff_with_context # diff_with_context, diff_only
96
134
  file_extensions_filter: [".cs", ".ts", ".py"]
97
135
  max_diff_files: 50
98
136
  max_comments_to_post: 20
99
137
  custom_prompt_file: review_context.local.md
138
+ rag:
139
+ enabled: true # requires local branch == PR target
140
+ max_chars: 40000
100
141
  project_context:
101
142
  enabled: true
102
143
  mode: on_demand # on_demand, full
@@ -143,11 +184,59 @@ src/
143
184
  tfs_client.py # Azure DevOps integration
144
185
  git_utils.py # Git diff processing
145
186
  formatter.py # Output formatting (terminal, markdown, JSON)
187
+ rag_engine.py # RAG context via git grep
146
188
 
147
189
  tests/
148
190
  test_*.py # Unit and integration tests
149
191
  ```
150
192
 
193
+ ## RAG Context
194
+
195
+ ### Current Implementation
196
+
197
+ The RAG engine enriches the LLM prompt with related code snippets found in the local repository:
198
+
199
+ 1. **Extract identifiers** — function and class names are parsed from the PR diff
200
+ 2. **Search** — `git grep` finds files containing those identifiers
201
+ 3. **Extract snippets** — ±10 lines around each match are included as read-only context
202
+
203
+ All operations run locally with no extra dependencies. The quality of RAG context depends entirely on the local repository state, which is why the **local branch must match the PR target branch**.
204
+
205
+ ### Recommended Stack for Enhanced RAG (Local & Open Source)
206
+
207
+ For teams wanting semantic similarity instead of keyword search, the recommended local stack is:
208
+
209
+ | Component | Library | Reason |
210
+ |---|---|---|
211
+ | **Vector database** | [ChromaDB](https://www.trychroma.com/) | Runs in-memory or persists to a local SQLite file — no server needed, `pip install chromadb` |
212
+ | **Embeddings** | [sentence-transformers](https://www.sbert.net/) | Generates vectors locally on CPU — no API calls, no cost |
213
+
214
+ Example integration pattern:
215
+
216
+ ```python
217
+ from sentence_transformers import SentenceTransformer
218
+ import chromadb
219
+
220
+ model = SentenceTransformer("all-MiniLM-L6-v2") # ~80 MB, CPU-friendly
221
+ client = chromadb.Client() # in-memory
222
+ collection = client.create_collection("repo-index")
223
+
224
+ # Index
225
+ collection.add(
226
+ documents=[snippet_text],
227
+ embeddings=model.encode([snippet_text]).tolist(),
228
+ ids=["file:line"],
229
+ )
230
+
231
+ # Query
232
+ results = collection.query(
233
+ query_embeddings=model.encode([query]).tolist(),
234
+ n_results=5,
235
+ )
236
+ ```
237
+
238
+ This stack keeps the CLI lightweight (`pip install`) and requires no external services or paid APIs.
239
+
151
240
  ### Run Tests
152
241
 
153
242
  ```bash
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-review-ai-cli
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
5
5
  License: MIT
6
6
  Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
@@ -48,10 +48,48 @@ Automated code review tool with Pull Request integration for Azure DevOps/TFS an
48
48
  - **Multiple LLM Providers** — OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
49
49
  - **Smart Filtering** — Filter by file extensions, limit diff size
50
50
  - **Project-aware PR Context** — Sends repository and linked work item context while restricting findings to modified PR lines
51
+ - **RAG Context** — Enriches the review with related code snippets found via `git grep` in the local repository
51
52
  - **Single Reviewer Context** — One Markdown context file with local override support
52
53
  - **Usage Tracking** — Store per-PR token usage and optional cost estimates
53
54
  - **Interactive CLI** — Menu-driven selection and confirmation
54
55
 
56
+ ## Local Repository Requirement
57
+
58
+ > **The CLI must be run from inside the local clone of the repository being reviewed.**
59
+
60
+ The PR diff is fetched from Azure DevOps/TFS, but several features depend on the local git state:
61
+
62
+ | Feature | Local dependency |
63
+ |---|---|
64
+ | PR diff | `git fetch` + three-dot diff against `origin/<branch>` |
65
+ | RAG context | `git grep` on the working tree |
66
+ | Branch validation | `git branch --show-current` |
67
+
68
+ ### Branch requirement when RAG is enabled
69
+
70
+ When `review.rag.enabled: true`, the local repository **must be checked out on the PR target branch** (e.g. `development`). If the local branch differs from the target, the review is blocked:
71
+
72
+ ```
73
+ Local branch mismatch: you are on 'main' but this PR targets 'development'.
74
+ RAG context would be built from the wrong branch, which may corrupt the review.
75
+ Please run: git checkout development
76
+ ```
77
+
78
+ **Example:**
79
+ ```bash
80
+ # PR: merge 'feature/my-feature' → 'development'
81
+ cd /path/to/my-repo # must be inside the repo
82
+ git checkout development # must match PR target branch
83
+ ai-review pr-review 42
84
+ ```
85
+
86
+ To skip the branch check entirely, disable RAG:
87
+ ```yaml
88
+ review:
89
+ rag:
90
+ enabled: false
91
+ ```
92
+
55
93
  ## Installation & Quick Start
56
94
 
57
95
  ### 1. Install Package
@@ -129,11 +167,14 @@ tfs:
129
167
  review:
130
168
  language: pt
131
169
  verbosity: detailed # or: quick, security
132
- scope: diff_with_context # diff_with_context, diff_only, full_code
170
+ scope: diff_with_context # diff_with_context, diff_only
133
171
  file_extensions_filter: [".cs", ".ts", ".py"]
134
172
  max_diff_files: 50
135
173
  max_comments_to_post: 20
136
174
  custom_prompt_file: review_context.local.md
175
+ rag:
176
+ enabled: true # requires local branch == PR target
177
+ max_chars: 40000
137
178
  project_context:
138
179
  enabled: true
139
180
  mode: on_demand # on_demand, full
@@ -180,11 +221,59 @@ src/
180
221
  tfs_client.py # Azure DevOps integration
181
222
  git_utils.py # Git diff processing
182
223
  formatter.py # Output formatting (terminal, markdown, JSON)
224
+ rag_engine.py # RAG context via git grep
183
225
 
184
226
  tests/
185
227
  test_*.py # Unit and integration tests
186
228
  ```
187
229
 
230
+ ## RAG Context
231
+
232
+ ### Current Implementation
233
+
234
+ The RAG engine enriches the LLM prompt with related code snippets found in the local repository:
235
+
236
+ 1. **Extract identifiers** — function and class names are parsed from the PR diff
237
+ 2. **Search** — `git grep` finds files containing those identifiers
238
+ 3. **Extract snippets** — ±10 lines around each match are included as read-only context
239
+
240
+ All operations run locally with no extra dependencies. The quality of RAG context depends entirely on the local repository state, which is why the **local branch must match the PR target branch**.
241
+
242
+ ### Recommended Stack for Enhanced RAG (Local & Open Source)
243
+
244
+ For teams wanting semantic similarity instead of keyword search, the recommended local stack is:
245
+
246
+ | Component | Library | Reason |
247
+ |---|---|---|
248
+ | **Vector database** | [ChromaDB](https://www.trychroma.com/) | Runs in-memory or persists to a local SQLite file — no server needed, `pip install chromadb` |
249
+ | **Embeddings** | [sentence-transformers](https://www.sbert.net/) | Generates vectors locally on CPU — no API calls, no cost |
250
+
251
+ Example integration pattern:
252
+
253
+ ```python
254
+ from sentence_transformers import SentenceTransformer
255
+ import chromadb
256
+
257
+ model = SentenceTransformer("all-MiniLM-L6-v2") # ~80 MB, CPU-friendly
258
+ client = chromadb.Client() # in-memory
259
+ collection = client.create_collection("repo-index")
260
+
261
+ # Index
262
+ collection.add(
263
+ documents=[snippet_text],
264
+ embeddings=model.encode([snippet_text]).tolist(),
265
+ ids=["file:line"],
266
+ )
267
+
268
+ # Query
269
+ results = collection.query(
270
+ query_embeddings=model.encode([query]).tolist(),
271
+ n_results=5,
272
+ )
273
+ ```
274
+
275
+ This stack keeps the CLI lightweight (`pip install`) and requires no external services or paid APIs.
276
+
188
277
  ### Run Tests
189
278
 
190
279
  ```bash
@@ -12,6 +12,7 @@ src/config.py
12
12
  src/formatter.py
13
13
  src/git_utils.py
14
14
  src/llm_client.py
15
+ src/rag_engine.py
15
16
  src/tfs_client.py
16
17
  src/usage_tracker.py
17
18
  src/prompts/config.yaml.template
@@ -21,5 +22,6 @@ tests/test_config.py
21
22
  tests/test_formatter.py
22
23
  tests/test_git_utils.py
23
24
  tests/test_llm_client.py
25
+ tests/test_rag_engine.py
24
26
  tests/test_tfs_client.py
25
27
  tests/test_usage_tracker.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-review-ai-cli"
7
- version = "1.2.0"
7
+ version = "1.3.0"
8
8
  description = "Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -84,6 +84,7 @@ from src.config import ReviewConfig, VALID_PROVIDERS
84
84
  from src.git_utils import GitUtils, GitError
85
85
  from src.llm_client import LLMClient, LLMError
86
86
  from src.formatter import ReviewFormatter, Colors, save_output
87
+ from src.rag_engine import obter_contexto_rag
87
88
  from src.usage_tracker import (
88
89
  append_usage_record,
89
90
  build_pr_usage_record,
@@ -94,7 +95,7 @@ from src.usage_tracker import (
94
95
  from src import __version__ as VERSION
95
96
 
96
97
 
97
- REVIEW_SCOPE_CHOICES = ["diff_only", "diff_with_context", "full_code"]
98
+ REVIEW_SCOPE_CHOICES = ["diff_only", "diff_with_context"]
98
99
 
99
100
 
100
101
  def _get_spinner_frames() -> list[str]:
@@ -263,7 +264,7 @@ def _add_global_options(parser: argparse.ArgumentParser) -> None:
263
264
  "--review-scope", default=None,
264
265
  choices=REVIEW_SCOPE_CHOICES,
265
266
  help=(
266
- "Review scope: diff_with_context (default), diff_only, or full_code"
267
+ "Review scope: diff_with_context (default) or diff_only"
267
268
  )
268
269
  )
269
270
  group_review.add_argument(
@@ -333,11 +334,6 @@ def _review_scope_context_note(review_scope: str) -> str:
333
334
  "Context will be used for understanding only; review comments remain "
334
335
  "limited to modified PR lines."
335
336
  )
336
- if scope == "full_code":
337
- return (
338
- "Review is running in full_code mode; full changed files are context, "
339
- "but comments remain limited to actual PR changes."
340
- )
341
337
  return "Review is running in diff_only mode."
342
338
 
343
339
 
@@ -786,7 +782,6 @@ def _comment_mentions_non_anchor_terms(comment: dict, anchor_text: str) -> bool:
786
782
  comment.get("comment", ""),
787
783
  comment.get("anchor_code", ""),
788
784
  comment.get("problematic_code", ""),
789
- comment.get("evidence", ""),
790
785
  ):
791
786
  if term not in anchor_text:
792
787
  return True
@@ -904,15 +899,15 @@ def _filter_comments_to_grounded_source_lines(
904
899
  discarded_grounding.append(comment)
905
900
  continue
906
901
 
907
- if not _text_contains_evidence(anchor_text, anchor_code):
902
+ if not evidence:
908
903
  discarded_grounding.append(comment)
909
904
  continue
910
905
 
911
- if not _text_contains_evidence(anchor_text, problematic_code):
906
+ if not _text_contains_evidence(anchor_text, anchor_code):
912
907
  discarded_grounding.append(comment)
913
908
  continue
914
909
 
915
- if not _text_contains_evidence(anchor_text, evidence):
910
+ if not _text_contains_evidence(anchor_text, problematic_code):
916
911
  discarded_grounding.append(comment)
917
912
  continue
918
913
 
@@ -924,10 +919,6 @@ def _filter_comments_to_grounded_source_lines(
924
919
  discarded_grounding.append(comment)
925
920
  continue
926
921
 
927
- if not _text_contains_evidence(source_text, evidence):
928
- discarded_grounding.append(comment)
929
- continue
930
-
931
922
  if _comment_mentions_absent_source_terms(comment, source_text):
932
923
  discarded_grounding.append(comment)
933
924
  continue
@@ -1381,19 +1372,29 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
1381
1372
  # Show PR details
1382
1373
  print(formatter.format_pr_details(pr_details))
1383
1374
 
1384
- # --- Get PR diff ---
1375
+ # --- Get PR diff via git local ---
1385
1376
  print(formatter.format_progress("Getting Pull Request diff"))
1386
1377
 
1378
+ _local_repo = (config.tfs_local_repo_path or "").strip() or os.getcwd()
1379
+ git_utils_pr = GitUtils(repo_path=_local_repo, pat=config.tfs_pat)
1380
+
1387
1381
  try:
1388
- diff = tfs.get_pull_request_diff(
1389
- repo_name,
1390
- pr_id,
1391
- review_scope=config.review_scope,
1392
- )
1382
+ target_ref, source_ref = tfs.obter_dados_pr(pr_id)
1393
1383
  except TFSError as exc:
1394
1384
  print(formatter.format_error(str(exc)))
1395
1385
  return 1
1396
1386
 
1387
+ try:
1388
+ git_utils_pr.fetch_merge_commit(source_ref)
1389
+ except GitError as exc:
1390
+ print(formatter.format_warning(f"Could not fetch source branch: {exc}"))
1391
+
1392
+ try:
1393
+ diff = git_utils_pr.get_pr_diff(target_ref, source_ref)
1394
+ except GitError as exc:
1395
+ print(formatter.format_error(str(exc)))
1396
+ return 1
1397
+
1397
1398
  if not diff.strip():
1398
1399
  print(formatter.format_warning("PR contains no code changes."))
1399
1400
  return 0
@@ -1411,8 +1412,13 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
1411
1412
  print(formatter.format_info("🔍 DRY-RUN mode: comments will NOT be posted"))
1412
1413
 
1413
1414
  # Get diff files summary
1414
- git_utils = GitUtils.__new__(GitUtils)
1415
- git_utils.repo_path = os.getcwd()
1415
+ git_utils = git_utils_pr
1416
+
1417
+ # --- Noise filter (binary, lock files, oversized sections) ---
1418
+ diff = git_utils_pr.filter_diff_noise(diff, config.max_diff_lines)
1419
+ if not diff.strip():
1420
+ print(formatter.format_warning("After filtering noise (binary/lock files), the diff is empty."))
1421
+ return 0
1416
1422
 
1417
1423
  # Filter extensions before limiting/truncating the diff sent to the LLM
1418
1424
  if config.file_extensions_filter:
@@ -1460,7 +1466,41 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
1460
1466
  ))
1461
1467
 
1462
1468
  use_contextual_review = review_scope == "diff_with_context"
1463
- load_changed_file_context = review_scope in ("diff_with_context", "full_code")
1469
+ load_changed_file_context = review_scope == "diff_with_context"
1470
+
1471
+ # --- RAG context ---
1472
+ rag_context = ""
1473
+ if config.rag_enabled and diff_truncated.strip():
1474
+ # Verify local branch matches the PR target branch to avoid RAG context contamination.
1475
+ _target_branch = target_ref.removeprefix("origin/")
1476
+ try:
1477
+ _local_branch = git_utils_pr.get_current_branch()
1478
+ except GitError as exc:
1479
+ print(formatter.format_error(
1480
+ f"Cannot determine local branch: {exc}\n"
1481
+ "Ensure the local repository is accessible and try again."
1482
+ ))
1483
+ return 1
1484
+
1485
+ if _local_branch != _target_branch:
1486
+ print(formatter.format_error(
1487
+ f"Local branch mismatch: you are on '{_local_branch}' "
1488
+ f"but this PR targets '{_target_branch}'.\n"
1489
+ f"RAG context would be built from the wrong branch, which may corrupt the review.\n"
1490
+ f"Please run: git checkout {_target_branch}"
1491
+ ))
1492
+ return 1
1493
+
1494
+ print(formatter.format_progress("Loading RAG context from local repository"))
1495
+ rag_context = obter_contexto_rag(
1496
+ diff_truncated,
1497
+ repo_path=git_utils.repo_path,
1498
+ max_chars=config.rag_max_chars,
1499
+ )
1500
+ if rag_context:
1501
+ print(formatter.format_info(
1502
+ f"RAG context loaded ({len(rag_context):,} characters)."
1503
+ ))
1464
1504
 
1465
1505
  work_item_context = ""
1466
1506
  linked_work_item_ids: list[int] | None = None
@@ -1604,7 +1644,7 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
1604
1644
  structured_comments = llm.review_pr_structured(
1605
1645
  diff=diff_truncated,
1606
1646
  files_summary=files_summary,
1607
- context=getattr(args, "context", ""),
1647
+ context="\n\n".join(filter(None, [getattr(args, "context", ""), rag_context])),
1608
1648
  review_scope=config.review_scope,
1609
1649
  project_context=project_context,
1610
1650
  work_item_context=work_item_context,
@@ -84,11 +84,12 @@ class ReviewConfig:
84
84
  tfs_verify_ssl: bool = True # Verify TLS certificates
85
85
  tfs_ca_bundle: str = "" # Path to corporate CA bundle (.pem)
86
86
  tfs_repository: str = "" # Default repository (empty = all)
87
+ tfs_local_repo_path: str = "" # Local clone path of the reviewed repo (empty = cwd)
87
88
 
88
89
  # --- Review -------------------------------------------------------
89
90
  review_language: str = "pt" # Review language (pt/en)
90
91
  verbosity: str = "detailed" # "quick" | "detailed" | "security"
91
- review_scope: str = "diff_with_context" # "diff_only" | "diff_with_context" | "full_code"
92
+ review_scope: str = "diff_with_context" # "diff_only" | "diff_with_context"
92
93
  max_diff_files: int = 50 # Max diff files sent to LLM
93
94
  max_diff_lines: int = 2000 # Max diff lines
94
95
  max_comments_to_post: int = 20 # Max actionable inline comments per review
@@ -141,6 +142,10 @@ class ReviewConfig:
141
142
  "Microsoft.VSTS.TCM.SystemInfo",
142
143
  ])
143
144
 
145
+ # --- RAG Context --------------------------------------------------
146
+ rag_enabled: bool = True # Enable RAG context retrieval
147
+ rag_max_chars: int = 40000 # Max characters for RAG context
148
+
144
149
  # --- PR Review ----------------------------------------------------
145
150
  auto_post_comments: bool = False # Post comments automatically
146
151
  dry_run: bool = False # Review without posting
@@ -260,6 +265,7 @@ class ReviewConfig:
260
265
  "tfs_verify_ssl": ("tfs", "verify_ssl"),
261
266
  "tfs_ca_bundle": ("tfs", "ca_bundle"),
262
267
  "tfs_repository": ("tfs", "repository"),
268
+ "tfs_local_repo_path": ("tfs", "local_repo_path"),
263
269
  # Review
264
270
  "review_language": ("review", "language"),
265
271
  "verbosity": ("review", "verbosity"),
@@ -284,6 +290,8 @@ class ReviewConfig:
284
290
  "work_item_context_max_items": ("review", "work_item_context", "max_items"),
285
291
  "work_item_context_max_chars": ("review", "work_item_context", "max_chars"),
286
292
  "work_item_context_fields": ("review", "work_item_context", "fields"),
293
+ "rag_enabled": ("review", "rag", "enabled"),
294
+ "rag_max_chars": ("review", "rag", "max_chars"),
287
295
  # PR
288
296
  "auto_post_comments": ("pr", "auto_post_comments"),
289
297
  "dry_run": ("pr", "dry_run"),
@@ -377,10 +385,10 @@ class ReviewConfig:
377
385
  "Use 'quick', 'detailed' or 'security'."
378
386
  )
379
387
 
380
- if self.review_scope not in ("diff_only", "diff_with_context", "full_code"):
388
+ if self.review_scope not in ("diff_only", "diff_with_context"):
381
389
  issues.append(
382
390
  f"Invalid review scope: '{self.review_scope}'. "
383
- "Use 'diff_only', 'diff_with_context' or 'full_code'."
391
+ "Use 'diff_only' or 'diff_with_context'."
384
392
  )
385
393
 
386
394
  if self.max_diff_files <= 0: