code-review-ai-cli 1.0.0__tar.gz → 1.0.1__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 (25) hide show
  1. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/PKG-INFO +56 -79
  2. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/README.md +55 -78
  3. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/PKG-INFO +56 -79
  4. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/SOURCES.txt +1 -0
  5. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/pyproject.toml +1 -1
  6. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/ai_review.py +42 -19
  7. code_review_ai_cli-1.0.1/src/prompts/review_prompt.md.template +42 -0
  8. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_ai_review.py +162 -1
  9. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/dependency_links.txt +0 -0
  10. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/entry_points.txt +0 -0
  11. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/requires.txt +0 -0
  12. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/top_level.txt +0 -0
  13. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/setup.cfg +0 -0
  14. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/__init__.py +0 -0
  15. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/config.py +0 -0
  16. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/formatter.py +0 -0
  17. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/git_utils.py +0 -0
  18. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/llm_client.py +0 -0
  19. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/prompts/config.yaml.template +0 -0
  20. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/tfs_client.py +0 -0
  21. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_config.py +0 -0
  22. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_formatter.py +0 -0
  23. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_git_utils.py +0 -0
  24. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_llm_client.py +0 -0
  25. {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_tfs_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-review-ai-cli
3
- Version: 1.0.0
3
+ Version: 1.0.1
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
@@ -78,22 +78,26 @@ pip install "code-review-ai-cli[dev]"
78
78
 
79
79
  ## Configuration
80
80
 
81
- After installing the package, generate a ready-to-edit `config.yaml` in your working directory:
81
+ After installing the package, generate ready-to-edit configuration files in your working directory:
82
82
 
83
83
  ```bash
84
84
  ai-review init
85
85
  ```
86
86
 
87
- This copies the bundled template with all available options and inline documentation:
87
+ This copies two bundled templates:
88
88
 
89
- ```
89
+ - **`config.yaml`** — all available options with inline documentation
90
+ - **`review_prompt.md`** — default review style rules, injected into every LLM prompt
91
+
92
+ ```text
90
93
  ✅ config.yaml created at: /home/user/my-project/config.yaml
91
- Edit it to add your credentials and preferences.
94
+ ✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
95
+ Edit them to add your credentials, preferences and review rules.
92
96
  ```
93
97
 
94
- If a `config.yaml` already exists you will be prompted before it is overwritten:
98
+ If either file already exists you will be prompted individually before it is overwritten:
95
99
 
96
- ```
100
+ ```text
97
101
  config.yaml already exists in the current directory.
98
102
  Overwrite? [y/N]
99
103
  ```
@@ -165,23 +169,22 @@ review:
165
169
 
166
170
  ### Markdown-Customizable Prompt
167
171
 
168
- You can adjust review rules, context, and examples in `review_prompt.md`.
169
- This file is loaded automatically and injected into LLM instructions on each run.
170
-
171
- Example in `config.yaml`:
172
-
173
- ```yaml
174
- review:
175
- custom_prompt_file: review_prompt.md
176
- ```
172
+ `ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
177
173
 
178
- Suggested usage for this file:
174
+ Edit it to tailor the review to your team:
179
175
 
180
176
  - Define comment tone and format
181
177
  - Add mandatory validation rules
182
178
  - Include business/architecture context
183
179
  - Add examples of good/bad comments
184
180
 
181
+ The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
182
+
183
+ ```yaml
184
+ review:
185
+ custom_prompt_file: review_prompt.md
186
+ ```
187
+
185
188
  ### Bedrock Example
186
189
 
187
190
  ```yaml
@@ -201,50 +204,23 @@ tfs:
201
204
  project: ProjectName
202
205
  pat: xxxxxxxxx
203
206
  ```
207
+
204
208
  Bedrock notes:
205
209
 
206
210
  - You can use `profile` or explicit credentials in YAML.
207
211
  - If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
208
212
 
209
- ## Review Flow
210
-
211
- The main `pr-review` workflow is:
212
-
213
- 1. load and validate configuration
214
- 2. fetch Pull Request metadata from Azure DevOps/TFS
215
- 3. fetch the PR diff
216
- 4. filter and truncate the diff according to configuration
217
- 5. request textual analysis and structured comments from the LLM provider
218
- 6. display a preview in the terminal
219
- 7. post inline or general PR comments when applicable
220
-
221
- ## Tests
222
-
223
- The project's functional coverage is reflected in the `tests/` folder, including:
224
-
225
- - `tests/test_ai_review.py` for the CLI and main workflow
226
- - `tests/test_config.py` for configuration and validation
227
- - `tests/test_formatter.py` for terminal/markdown/json rendering
228
- - `tests/test_git_utils.py` for diffs and Git utilities
229
- - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
230
- - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
231
-
232
- Run the suite:
233
-
234
- ```bash
235
- python -m pytest --cov=src --cov-report=term
236
- ```
237
-
238
213
  ## CLI Usage
239
214
 
240
215
  ### Help
216
+
241
217
  ```bash
242
- python src/ai_review.py --help
218
+ ai-review pr-review --help
243
219
  ```
244
220
 
245
221
  ### Bootstrap configuration
246
222
 
247
- Generate a `config.yaml` template in the current directory:
223
+ Generate `config.yaml` and `review_prompt.md` templates in the current directory:
248
224
 
249
225
  ```bash
250
226
  ai-review init
@@ -253,7 +229,7 @@ ai-review init
253
229
  ### Interactive Mode
254
230
 
255
231
  ```bash
256
- python ai_review.py
232
+ ai-review pr-review
257
233
  ```
258
234
 
259
235
  ### Pull Request Review
@@ -261,51 +237,51 @@ python ai_review.py
261
237
  List PRs and select interactively:
262
238
 
263
239
  ```bash
264
- python ai_review.py pr-review
240
+ ai-review pr-review pr-review
265
241
  ```
266
242
 
267
243
  Review a specific PR:
268
244
 
269
245
  ```bash
270
- python ai_review.py pr-review 42
246
+ ai-review pr-review pr-review 42
271
247
  ```
272
248
 
273
249
  Dry-run:
274
250
 
275
251
  ```bash
276
- python ai_review.py pr-review 42 --dry-run
252
+ ai-review pr-review pr-review 42 --dry-run
277
253
  ```
278
254
 
279
255
  Full review of changed files (in addition to diff-focused review):
280
256
 
281
257
  ```bash
282
- python ai_review.py pr-review 42 --review-scope full_code
258
+ ai-review pr-review pr-review 42 --review-scope full_code
283
259
  ```
284
260
 
285
261
  Automatic posting (without confirmation):
286
262
 
287
263
  ```bash
288
- python ai_review.py pr-review 42 --auto-post
264
+ ai-review pr-review pr-review 42 --auto-post
289
265
  ```
290
266
 
291
267
  Filter PRs in interactive selection:
292
268
 
293
269
  ```bash
294
- python ai_review.py pr-review --author "John Smith" --target-branch main
270
+ ai-review pr-review pr-review --author "John Smith" --target-branch main
295
271
  ```
296
272
 
297
273
  Choose provider/model via CLI:
298
274
 
299
275
  ```bash
300
- python ai_review.py pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
276
+ ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
301
277
  ```
302
278
 
303
279
  ### List Pull Requests
304
280
 
305
281
  ```bash
306
- python ai_review.py list-prs
307
- python ai_review.py list-prs --status completed
308
- python ai_review.py list-prs --repo-name backend --author "John"
282
+ ai-review pr-review list-prs
283
+ ai-review pr-review list-prs --status completed
284
+ ai-review pr-review list-prs --repo-name backend --author "John"
309
285
  ```
310
286
 
311
287
  ## Execution Flow
@@ -314,7 +290,7 @@ The diagram below summarizes how the review application moves from CLI entry to
314
290
 
315
291
  ```mermaid
316
292
  flowchart TD
317
- A[Start: python ai_review.py] --> B{Arguments provided?}
293
+ A[Start: ai-review pr-review] --> B{Arguments provided?}
318
294
  B -->|No| C[Interactive mode]
319
295
  B -->|Yes| D[Parse CLI command]
320
296
 
@@ -364,7 +340,7 @@ flowchart TD
364
340
  ### `pr-review`
365
341
 
366
342
  ```bash
367
- python ai_review.py pr-review [pr_id]
343
+ ai-review pr-review pr-review [pr_id]
368
344
  ```
369
345
 
370
346
  Options:
@@ -388,7 +364,7 @@ Options:
388
364
  ### `list-prs`
389
365
 
390
366
  ```bash
391
- python ai_review.py list-prs
367
+ ai-review pr-review list-prs
392
368
  ```
393
369
 
394
370
  Options:
@@ -399,10 +375,10 @@ Options:
399
375
 
400
376
  ## Available VS Code Tasks
401
377
 
402
- - `🌟 AI Review: Pull Request (Interactive)`
403
- - `🌟 AI Review: PR (Dry-Run)`
404
- - `📋 AI Review: List Active PRs`
405
- - `🤖 AI Review: Interactive Mode`
378
+ - `AI Review: Pull Request (Interactive)`
379
+ - `AI Review: PR (Dry-Run)`
380
+ - `AI Review: List Active PRs`
381
+ - `AI Review: Interactive Mode`
406
382
 
407
383
  ## Troubleshooting
408
384
 
@@ -424,18 +400,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
424
400
  - Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
425
401
  - Validate AWS credentials (`profile` or explicit keys).
426
402
 
427
- ## Architecture
403
+ ## Tests
428
404
 
429
- ```text
430
- ai_code_review_script/
431
- ├── src/
432
- │ ├── config.py # YAML-only configuration
433
- │ ├── ai_review.py # Main PR CLI and workflow
434
- │ ├── llm_client.py # LLM provider integration (includes Bedrock)
435
- │ ├── tfs_client.py # Azure DevOps/TFS (PRs and comments)
436
- │ ├── formatter.py # Output formatting
437
- │ └── git_utils.py # Utilities for diff parsing/truncation
438
- ├── config.yaml # Single configuration file
439
- ├── requirements.txt # Python dependencies
440
- └── .vscode/tasks.json # PR review tasks
405
+ The project's functional coverage is reflected in the `tests/` folder, including:
406
+
407
+ - `tests/test_ai_review.py` for the CLI and main workflow
408
+ - `tests/test_config.py` for configuration and validation
409
+ - `tests/test_formatter.py` for terminal/markdown/json rendering
410
+ - `tests/test_git_utils.py` for diffs and Git utilities
411
+ - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
412
+ - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
413
+
414
+ Run the suite:
415
+
416
+ ```bash
417
+ python -m pytest --cov=src --cov-report=term
441
418
  ```
@@ -41,22 +41,26 @@ pip install "code-review-ai-cli[dev]"
41
41
 
42
42
  ## Configuration
43
43
 
44
- After installing the package, generate a ready-to-edit `config.yaml` in your working directory:
44
+ After installing the package, generate ready-to-edit configuration files in your working directory:
45
45
 
46
46
  ```bash
47
47
  ai-review init
48
48
  ```
49
49
 
50
- This copies the bundled template with all available options and inline documentation:
50
+ This copies two bundled templates:
51
51
 
52
- ```
52
+ - **`config.yaml`** — all available options with inline documentation
53
+ - **`review_prompt.md`** — default review style rules, injected into every LLM prompt
54
+
55
+ ```text
53
56
  ✅ config.yaml created at: /home/user/my-project/config.yaml
54
- Edit it to add your credentials and preferences.
57
+ ✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
58
+ Edit them to add your credentials, preferences and review rules.
55
59
  ```
56
60
 
57
- If a `config.yaml` already exists you will be prompted before it is overwritten:
61
+ If either file already exists you will be prompted individually before it is overwritten:
58
62
 
59
- ```
63
+ ```text
60
64
  config.yaml already exists in the current directory.
61
65
  Overwrite? [y/N]
62
66
  ```
@@ -128,23 +132,22 @@ review:
128
132
 
129
133
  ### Markdown-Customizable Prompt
130
134
 
131
- You can adjust review rules, context, and examples in `review_prompt.md`.
132
- This file is loaded automatically and injected into LLM instructions on each run.
133
-
134
- Example in `config.yaml`:
135
-
136
- ```yaml
137
- review:
138
- custom_prompt_file: review_prompt.md
139
- ```
135
+ `ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
140
136
 
141
- Suggested usage for this file:
137
+ Edit it to tailor the review to your team:
142
138
 
143
139
  - Define comment tone and format
144
140
  - Add mandatory validation rules
145
141
  - Include business/architecture context
146
142
  - Add examples of good/bad comments
147
143
 
144
+ The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
145
+
146
+ ```yaml
147
+ review:
148
+ custom_prompt_file: review_prompt.md
149
+ ```
150
+
148
151
  ### Bedrock Example
149
152
 
150
153
  ```yaml
@@ -164,50 +167,23 @@ tfs:
164
167
  project: ProjectName
165
168
  pat: xxxxxxxxx
166
169
  ```
170
+
167
171
  Bedrock notes:
168
172
 
169
173
  - You can use `profile` or explicit credentials in YAML.
170
174
  - If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
171
175
 
172
- ## Review Flow
173
-
174
- The main `pr-review` workflow is:
175
-
176
- 1. load and validate configuration
177
- 2. fetch Pull Request metadata from Azure DevOps/TFS
178
- 3. fetch the PR diff
179
- 4. filter and truncate the diff according to configuration
180
- 5. request textual analysis and structured comments from the LLM provider
181
- 6. display a preview in the terminal
182
- 7. post inline or general PR comments when applicable
183
-
184
- ## Tests
185
-
186
- The project's functional coverage is reflected in the `tests/` folder, including:
187
-
188
- - `tests/test_ai_review.py` for the CLI and main workflow
189
- - `tests/test_config.py` for configuration and validation
190
- - `tests/test_formatter.py` for terminal/markdown/json rendering
191
- - `tests/test_git_utils.py` for diffs and Git utilities
192
- - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
193
- - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
194
-
195
- Run the suite:
196
-
197
- ```bash
198
- python -m pytest --cov=src --cov-report=term
199
- ```
200
-
201
176
  ## CLI Usage
202
177
 
203
178
  ### Help
179
+
204
180
  ```bash
205
- python src/ai_review.py --help
181
+ ai-review pr-review --help
206
182
  ```
207
183
 
208
184
  ### Bootstrap configuration
209
185
 
210
- Generate a `config.yaml` template in the current directory:
186
+ Generate `config.yaml` and `review_prompt.md` templates in the current directory:
211
187
 
212
188
  ```bash
213
189
  ai-review init
@@ -216,7 +192,7 @@ ai-review init
216
192
  ### Interactive Mode
217
193
 
218
194
  ```bash
219
- python ai_review.py
195
+ ai-review pr-review
220
196
  ```
221
197
 
222
198
  ### Pull Request Review
@@ -224,51 +200,51 @@ python ai_review.py
224
200
  List PRs and select interactively:
225
201
 
226
202
  ```bash
227
- python ai_review.py pr-review
203
+ ai-review pr-review pr-review
228
204
  ```
229
205
 
230
206
  Review a specific PR:
231
207
 
232
208
  ```bash
233
- python ai_review.py pr-review 42
209
+ ai-review pr-review pr-review 42
234
210
  ```
235
211
 
236
212
  Dry-run:
237
213
 
238
214
  ```bash
239
- python ai_review.py pr-review 42 --dry-run
215
+ ai-review pr-review pr-review 42 --dry-run
240
216
  ```
241
217
 
242
218
  Full review of changed files (in addition to diff-focused review):
243
219
 
244
220
  ```bash
245
- python ai_review.py pr-review 42 --review-scope full_code
221
+ ai-review pr-review pr-review 42 --review-scope full_code
246
222
  ```
247
223
 
248
224
  Automatic posting (without confirmation):
249
225
 
250
226
  ```bash
251
- python ai_review.py pr-review 42 --auto-post
227
+ ai-review pr-review pr-review 42 --auto-post
252
228
  ```
253
229
 
254
230
  Filter PRs in interactive selection:
255
231
 
256
232
  ```bash
257
- python ai_review.py pr-review --author "John Smith" --target-branch main
233
+ ai-review pr-review pr-review --author "John Smith" --target-branch main
258
234
  ```
259
235
 
260
236
  Choose provider/model via CLI:
261
237
 
262
238
  ```bash
263
- python ai_review.py pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
239
+ ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
264
240
  ```
265
241
 
266
242
  ### List Pull Requests
267
243
 
268
244
  ```bash
269
- python ai_review.py list-prs
270
- python ai_review.py list-prs --status completed
271
- python ai_review.py list-prs --repo-name backend --author "John"
245
+ ai-review pr-review list-prs
246
+ ai-review pr-review list-prs --status completed
247
+ ai-review pr-review list-prs --repo-name backend --author "John"
272
248
  ```
273
249
 
274
250
  ## Execution Flow
@@ -277,7 +253,7 @@ The diagram below summarizes how the review application moves from CLI entry to
277
253
 
278
254
  ```mermaid
279
255
  flowchart TD
280
- A[Start: python ai_review.py] --> B{Arguments provided?}
256
+ A[Start: ai-review pr-review] --> B{Arguments provided?}
281
257
  B -->|No| C[Interactive mode]
282
258
  B -->|Yes| D[Parse CLI command]
283
259
 
@@ -327,7 +303,7 @@ flowchart TD
327
303
  ### `pr-review`
328
304
 
329
305
  ```bash
330
- python ai_review.py pr-review [pr_id]
306
+ ai-review pr-review pr-review [pr_id]
331
307
  ```
332
308
 
333
309
  Options:
@@ -351,7 +327,7 @@ Options:
351
327
  ### `list-prs`
352
328
 
353
329
  ```bash
354
- python ai_review.py list-prs
330
+ ai-review pr-review list-prs
355
331
  ```
356
332
 
357
333
  Options:
@@ -362,10 +338,10 @@ Options:
362
338
 
363
339
  ## Available VS Code Tasks
364
340
 
365
- - `🌟 AI Review: Pull Request (Interactive)`
366
- - `🌟 AI Review: PR (Dry-Run)`
367
- - `📋 AI Review: List Active PRs`
368
- - `🤖 AI Review: Interactive Mode`
341
+ - `AI Review: Pull Request (Interactive)`
342
+ - `AI Review: PR (Dry-Run)`
343
+ - `AI Review: List Active PRs`
344
+ - `AI Review: Interactive Mode`
369
345
 
370
346
  ## Troubleshooting
371
347
 
@@ -387,18 +363,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
387
363
  - Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
388
364
  - Validate AWS credentials (`profile` or explicit keys).
389
365
 
390
- ## Architecture
366
+ ## Tests
391
367
 
392
- ```text
393
- ai_code_review_script/
394
- ├── src/
395
- │ ├── config.py # YAML-only configuration
396
- │ ├── ai_review.py # Main PR CLI and workflow
397
- │ ├── llm_client.py # LLM provider integration (includes Bedrock)
398
- │ ├── tfs_client.py # Azure DevOps/TFS (PRs and comments)
399
- │ ├── formatter.py # Output formatting
400
- │ └── git_utils.py # Utilities for diff parsing/truncation
401
- ├── config.yaml # Single configuration file
402
- ├── requirements.txt # Python dependencies
403
- └── .vscode/tasks.json # PR review tasks
368
+ The project's functional coverage is reflected in the `tests/` folder, including:
369
+
370
+ - `tests/test_ai_review.py` for the CLI and main workflow
371
+ - `tests/test_config.py` for configuration and validation
372
+ - `tests/test_formatter.py` for terminal/markdown/json rendering
373
+ - `tests/test_git_utils.py` for diffs and Git utilities
374
+ - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
375
+ - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
376
+
377
+ Run the suite:
378
+
379
+ ```bash
380
+ python -m pytest --cov=src --cov-report=term
404
381
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-review-ai-cli
3
- Version: 1.0.0
3
+ Version: 1.0.1
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
@@ -78,22 +78,26 @@ pip install "code-review-ai-cli[dev]"
78
78
 
79
79
  ## Configuration
80
80
 
81
- After installing the package, generate a ready-to-edit `config.yaml` in your working directory:
81
+ After installing the package, generate ready-to-edit configuration files in your working directory:
82
82
 
83
83
  ```bash
84
84
  ai-review init
85
85
  ```
86
86
 
87
- This copies the bundled template with all available options and inline documentation:
87
+ This copies two bundled templates:
88
88
 
89
- ```
89
+ - **`config.yaml`** — all available options with inline documentation
90
+ - **`review_prompt.md`** — default review style rules, injected into every LLM prompt
91
+
92
+ ```text
90
93
  ✅ config.yaml created at: /home/user/my-project/config.yaml
91
- Edit it to add your credentials and preferences.
94
+ ✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
95
+ Edit them to add your credentials, preferences and review rules.
92
96
  ```
93
97
 
94
- If a `config.yaml` already exists you will be prompted before it is overwritten:
98
+ If either file already exists you will be prompted individually before it is overwritten:
95
99
 
96
- ```
100
+ ```text
97
101
  config.yaml already exists in the current directory.
98
102
  Overwrite? [y/N]
99
103
  ```
@@ -165,23 +169,22 @@ review:
165
169
 
166
170
  ### Markdown-Customizable Prompt
167
171
 
168
- You can adjust review rules, context, and examples in `review_prompt.md`.
169
- This file is loaded automatically and injected into LLM instructions on each run.
170
-
171
- Example in `config.yaml`:
172
-
173
- ```yaml
174
- review:
175
- custom_prompt_file: review_prompt.md
176
- ```
172
+ `ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
177
173
 
178
- Suggested usage for this file:
174
+ Edit it to tailor the review to your team:
179
175
 
180
176
  - Define comment tone and format
181
177
  - Add mandatory validation rules
182
178
  - Include business/architecture context
183
179
  - Add examples of good/bad comments
184
180
 
181
+ The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
182
+
183
+ ```yaml
184
+ review:
185
+ custom_prompt_file: review_prompt.md
186
+ ```
187
+
185
188
  ### Bedrock Example
186
189
 
187
190
  ```yaml
@@ -201,50 +204,23 @@ tfs:
201
204
  project: ProjectName
202
205
  pat: xxxxxxxxx
203
206
  ```
207
+
204
208
  Bedrock notes:
205
209
 
206
210
  - You can use `profile` or explicit credentials in YAML.
207
211
  - If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
208
212
 
209
- ## Review Flow
210
-
211
- The main `pr-review` workflow is:
212
-
213
- 1. load and validate configuration
214
- 2. fetch Pull Request metadata from Azure DevOps/TFS
215
- 3. fetch the PR diff
216
- 4. filter and truncate the diff according to configuration
217
- 5. request textual analysis and structured comments from the LLM provider
218
- 6. display a preview in the terminal
219
- 7. post inline or general PR comments when applicable
220
-
221
- ## Tests
222
-
223
- The project's functional coverage is reflected in the `tests/` folder, including:
224
-
225
- - `tests/test_ai_review.py` for the CLI and main workflow
226
- - `tests/test_config.py` for configuration and validation
227
- - `tests/test_formatter.py` for terminal/markdown/json rendering
228
- - `tests/test_git_utils.py` for diffs and Git utilities
229
- - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
230
- - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
231
-
232
- Run the suite:
233
-
234
- ```bash
235
- python -m pytest --cov=src --cov-report=term
236
- ```
237
-
238
213
  ## CLI Usage
239
214
 
240
215
  ### Help
216
+
241
217
  ```bash
242
- python src/ai_review.py --help
218
+ ai-review pr-review --help
243
219
  ```
244
220
 
245
221
  ### Bootstrap configuration
246
222
 
247
- Generate a `config.yaml` template in the current directory:
223
+ Generate `config.yaml` and `review_prompt.md` templates in the current directory:
248
224
 
249
225
  ```bash
250
226
  ai-review init
@@ -253,7 +229,7 @@ ai-review init
253
229
  ### Interactive Mode
254
230
 
255
231
  ```bash
256
- python ai_review.py
232
+ ai-review pr-review
257
233
  ```
258
234
 
259
235
  ### Pull Request Review
@@ -261,51 +237,51 @@ python ai_review.py
261
237
  List PRs and select interactively:
262
238
 
263
239
  ```bash
264
- python ai_review.py pr-review
240
+ ai-review pr-review pr-review
265
241
  ```
266
242
 
267
243
  Review a specific PR:
268
244
 
269
245
  ```bash
270
- python ai_review.py pr-review 42
246
+ ai-review pr-review pr-review 42
271
247
  ```
272
248
 
273
249
  Dry-run:
274
250
 
275
251
  ```bash
276
- python ai_review.py pr-review 42 --dry-run
252
+ ai-review pr-review pr-review 42 --dry-run
277
253
  ```
278
254
 
279
255
  Full review of changed files (in addition to diff-focused review):
280
256
 
281
257
  ```bash
282
- python ai_review.py pr-review 42 --review-scope full_code
258
+ ai-review pr-review pr-review 42 --review-scope full_code
283
259
  ```
284
260
 
285
261
  Automatic posting (without confirmation):
286
262
 
287
263
  ```bash
288
- python ai_review.py pr-review 42 --auto-post
264
+ ai-review pr-review pr-review 42 --auto-post
289
265
  ```
290
266
 
291
267
  Filter PRs in interactive selection:
292
268
 
293
269
  ```bash
294
- python ai_review.py pr-review --author "John Smith" --target-branch main
270
+ ai-review pr-review pr-review --author "John Smith" --target-branch main
295
271
  ```
296
272
 
297
273
  Choose provider/model via CLI:
298
274
 
299
275
  ```bash
300
- python ai_review.py pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
276
+ ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
301
277
  ```
302
278
 
303
279
  ### List Pull Requests
304
280
 
305
281
  ```bash
306
- python ai_review.py list-prs
307
- python ai_review.py list-prs --status completed
308
- python ai_review.py list-prs --repo-name backend --author "John"
282
+ ai-review pr-review list-prs
283
+ ai-review pr-review list-prs --status completed
284
+ ai-review pr-review list-prs --repo-name backend --author "John"
309
285
  ```
310
286
 
311
287
  ## Execution Flow
@@ -314,7 +290,7 @@ The diagram below summarizes how the review application moves from CLI entry to
314
290
 
315
291
  ```mermaid
316
292
  flowchart TD
317
- A[Start: python ai_review.py] --> B{Arguments provided?}
293
+ A[Start: ai-review pr-review] --> B{Arguments provided?}
318
294
  B -->|No| C[Interactive mode]
319
295
  B -->|Yes| D[Parse CLI command]
320
296
 
@@ -364,7 +340,7 @@ flowchart TD
364
340
  ### `pr-review`
365
341
 
366
342
  ```bash
367
- python ai_review.py pr-review [pr_id]
343
+ ai-review pr-review pr-review [pr_id]
368
344
  ```
369
345
 
370
346
  Options:
@@ -388,7 +364,7 @@ Options:
388
364
  ### `list-prs`
389
365
 
390
366
  ```bash
391
- python ai_review.py list-prs
367
+ ai-review pr-review list-prs
392
368
  ```
393
369
 
394
370
  Options:
@@ -399,10 +375,10 @@ Options:
399
375
 
400
376
  ## Available VS Code Tasks
401
377
 
402
- - `🌟 AI Review: Pull Request (Interactive)`
403
- - `🌟 AI Review: PR (Dry-Run)`
404
- - `📋 AI Review: List Active PRs`
405
- - `🤖 AI Review: Interactive Mode`
378
+ - `AI Review: Pull Request (Interactive)`
379
+ - `AI Review: PR (Dry-Run)`
380
+ - `AI Review: List Active PRs`
381
+ - `AI Review: Interactive Mode`
406
382
 
407
383
  ## Troubleshooting
408
384
 
@@ -424,18 +400,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
424
400
  - Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
425
401
  - Validate AWS credentials (`profile` or explicit keys).
426
402
 
427
- ## Architecture
403
+ ## Tests
428
404
 
429
- ```text
430
- ai_code_review_script/
431
- ├── src/
432
- │ ├── config.py # YAML-only configuration
433
- │ ├── ai_review.py # Main PR CLI and workflow
434
- │ ├── llm_client.py # LLM provider integration (includes Bedrock)
435
- │ ├── tfs_client.py # Azure DevOps/TFS (PRs and comments)
436
- │ ├── formatter.py # Output formatting
437
- │ └── git_utils.py # Utilities for diff parsing/truncation
438
- ├── config.yaml # Single configuration file
439
- ├── requirements.txt # Python dependencies
440
- └── .vscode/tasks.json # PR review tasks
405
+ The project's functional coverage is reflected in the `tests/` folder, including:
406
+
407
+ - `tests/test_ai_review.py` for the CLI and main workflow
408
+ - `tests/test_config.py` for configuration and validation
409
+ - `tests/test_formatter.py` for terminal/markdown/json rendering
410
+ - `tests/test_git_utils.py` for diffs and Git utilities
411
+ - `tests/test_llm_client.py` for prompts, parsing, and LLM providers
412
+ - `tests/test_tfs_client.py` for TFS/Azure DevOps integration
413
+
414
+ Run the suite:
415
+
416
+ ```bash
417
+ python -m pytest --cov=src --cov-report=term
441
418
  ```
@@ -14,6 +14,7 @@ src/git_utils.py
14
14
  src/llm_client.py
15
15
  src/tfs_client.py
16
16
  src/prompts/config.yaml.template
17
+ src/prompts/review_prompt.md.template
17
18
  tests/test_ai_review.py
18
19
  tests/test_config.py
19
20
  tests/test_formatter.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.0.0"
7
+ version = "1.0.1"
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"
@@ -40,6 +40,7 @@ Version: see pyproject.toml
40
40
  """
41
41
 
42
42
  import argparse
43
+ import importlib.resources
43
44
  import os
44
45
  import sys
45
46
  import time
@@ -872,16 +873,16 @@ def _show_config(config: ReviewConfig) -> None:
872
873
  # Init command
873
874
  # ---------------------------------------------------------------------------
874
875
  def cmd_init() -> int:
875
- """Copies a config.yaml template to the current working directory.
876
+ """Copies a config.yaml template and review_prompt.md to the current working directory.
876
877
 
877
878
  Creates a ``config.yaml`` file pre-populated with all available options
878
- and inline documentation. If the file already exists in the current
879
- directory the user is prompted for confirmation before overwriting.
879
+ and inline documentation, and a ``review_prompt.md`` file with default
880
+ review style rules. If either file already exists in the current directory
881
+ the user is prompted for confirmation before overwriting.
880
882
 
881
- The template is bundled with the package at
882
- ``src/prompts/config.yaml.template`` and is resolved at runtime via
883
- :mod:`importlib.resources`, so it works regardless of how the package
884
- was installed.
883
+ Both files are bundled with the package at ``src/prompts/`` and are
884
+ resolved at runtime via :mod:`importlib.resources`, so they work
885
+ regardless of how the package was installed.
885
886
 
886
887
  Returns:
887
888
  int: Exit code. ``0`` on success or user cancellation, ``1`` on error.
@@ -891,14 +892,15 @@ def cmd_init() -> int:
891
892
 
892
893
  $ ai-review init
893
894
  ✅ config.yaml created at: /home/user/my-project/config.yaml
894
- Edit it to add your credentials and preferences.
895
+ ✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
896
+ Edit them to add your credentials, preferences and review rules.
895
897
  """
896
- import importlib.resources as pkg_resources
897
-
898
- dest = os.path.join(os.getcwd(), "config.yaml")
898
+ cwd = os.getcwd()
899
899
  c = Colors()
900
900
 
901
- if os.path.exists(dest):
901
+ # --- config.yaml ---
902
+ config_dest = os.path.join(cwd, "config.yaml")
903
+ if os.path.exists(config_dest):
902
904
  print(f"{c.YELLOW}config.yaml already exists in the current directory.{c.RESET}")
903
905
  answer = input("Overwrite? [y/N] ").strip().lower()
904
906
  if answer != "y":
@@ -906,17 +908,38 @@ def cmd_init() -> int:
906
908
  return 0
907
909
 
908
910
  try:
909
- ref = pkg_resources.files("src.prompts").joinpath("config.yaml.template")
910
- template_content = ref.read_text(encoding="utf-8")
911
+ ref = importlib.resources.files("src.prompts").joinpath("config.yaml.template")
912
+ config_content = ref.read_text(encoding="utf-8")
913
+ except (FileNotFoundError, TypeError) as exc:
914
+ print(f"{c.RED}Error: could not locate config template: {exc}{c.RESET}")
915
+ return 1
916
+
917
+ with open(config_dest, "w", encoding="utf-8") as fh:
918
+ fh.write(config_content)
919
+
920
+ # --- review_prompt.md ---
921
+ prompt_dest = os.path.join(cwd, "review_prompt.md")
922
+ if os.path.exists(prompt_dest):
923
+ print(f"{c.YELLOW}review_prompt.md already exists in the current directory.{c.RESET}")
924
+ answer = input("Overwrite? [y/N] ").strip().lower()
925
+ if answer != "y":
926
+ print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {config_dest}")
927
+ print(" Skipped review_prompt.md (kept existing).")
928
+ return 0
929
+
930
+ try:
931
+ ref = importlib.resources.files("src.prompts").joinpath("review_prompt.md.template")
932
+ prompt_content = ref.read_text(encoding="utf-8")
911
933
  except (FileNotFoundError, TypeError) as exc:
912
- print(f"{c.RED}Error: could not locate template file: {exc}{c.RESET}")
934
+ print(f"{c.RED}Error: could not locate review_prompt template: {exc}{c.RESET}")
913
935
  return 1
914
936
 
915
- with open(dest, "w", encoding="utf-8") as fh:
916
- fh.write(template_content)
937
+ with open(prompt_dest, "w", encoding="utf-8") as fh:
938
+ fh.write(prompt_content)
917
939
 
918
- print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {dest}")
919
- print(f" Edit it to add your credentials and preferences.")
940
+ print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {config_dest}")
941
+ print(f"{c.GREEN}✅ review_prompt.md created at:{c.RESET} {prompt_dest}")
942
+ print(" Edit them to add your credentials, preferences and review rules.")
920
943
  return 0
921
944
 
922
945
 
@@ -0,0 +1,42 @@
1
+ ## Style Rules
2
+ - Be direct and concise.
3
+ - No greetings.
4
+ - No emojis.
5
+ - Include file and line whenever possible.
6
+
7
+ ## Project Context
8
+ - Focus on practical findings that can be posted as PR comments.
9
+
10
+ ## Team Preferences
11
+ - Prioritize actionable comments over long explanations.
12
+ - Prefer concrete fix suggestions.
13
+ - Avoid style-only comments unless they affect maintainability.
14
+
15
+ ## Good Comment Examples
16
+ - "[src/service.py:128] Missing timeout in external HTTP call. Add timeout and handle exceptions to avoid blocking requests."
17
+ - "[src/auth.py:57] Token is logged in plain text. Remove sensitive data from logs."
18
+
19
+ ## Bad Comment Examples
20
+ - "Great work team!"
21
+ - "As a senior reviewer, I think..."
22
+ - "Maybe improve this part"
23
+
24
+ ## Universal Rules (all languages)
25
+
26
+ ### Security
27
+ - No hardcoded secrets, credentials, or tokens
28
+ - Validate and sanitize all external inputs
29
+ - No SQL/command injection vectors
30
+ - Least privilege principle applied
31
+
32
+ ### Code Quality
33
+ - Single Responsibility Principle per function/class
34
+ - No dead code, commented-out blocks, or TODOs without tickets
35
+ - Meaningful names (no abbreviations unless domain-standard)
36
+ - Max function length: \~30 lines; max file: \~300 lines
37
+ - DRY: no duplicated logic
38
+
39
+ ### Error Handling
40
+ - Errors must be caught, logged, and propagated correctly
41
+ - No silent catches (`catch {}` or `catch (e) {}`)
42
+ - Use typed/domain exceptions where applicable
@@ -390,4 +390,165 @@ def test_main_prints_help_when_no_command_is_parsed(mocker) -> None:
390
390
  mocker.patch("src.ai_review.build_parser", return_value=parser)
391
391
 
392
392
  assert ai_review.main() == 0
393
- parser.print_help.assert_called_once_with()
393
+ parser.print_help.assert_called_once_with()
394
+
395
+
396
+ # ---------------------------------------------------------------------------
397
+ # cmd_init
398
+ # ---------------------------------------------------------------------------
399
+
400
+ def test_cmd_init_creates_both_files(mocker, tmp_path) -> None:
401
+ """It should create config.yaml and review_prompt.md in the current directory."""
402
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
403
+ mocker.patch(
404
+ "src.ai_review.importlib.resources.files",
405
+ side_effect=_fake_pkg_resources,
406
+ )
407
+ mocker.patch("builtins.print")
408
+
409
+ result = ai_review.cmd_init()
410
+
411
+ assert result == 0
412
+ assert (tmp_path / "config.yaml").read_text() == "config-template"
413
+ assert (tmp_path / "review_prompt.md").read_text() == "prompt-template"
414
+
415
+
416
+ def test_cmd_init_aborts_when_user_declines_config_overwrite(mocker, tmp_path) -> None:
417
+ """It should abort without writing either file when user declines config overwrite."""
418
+ (tmp_path / "config.yaml").write_text("existing")
419
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
420
+ mocker.patch("builtins.input", return_value="n")
421
+ mocker.patch("builtins.print")
422
+
423
+ result = ai_review.cmd_init()
424
+
425
+ assert result == 0
426
+ assert (tmp_path / "config.yaml").read_text() == "existing"
427
+ assert not (tmp_path / "review_prompt.md").exists()
428
+
429
+
430
+ def test_cmd_init_skips_prompt_overwrite_when_user_declines(mocker, tmp_path) -> None:
431
+ """It should write config.yaml but keep existing review_prompt.md when user declines."""
432
+ (tmp_path / "review_prompt.md").write_text("existing-prompt")
433
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
434
+ mocker.patch(
435
+ "src.ai_review.importlib.resources.files",
436
+ side_effect=_fake_pkg_resources,
437
+ )
438
+ mocker.patch("builtins.input", return_value="n")
439
+ mocker.patch("builtins.print")
440
+
441
+ result = ai_review.cmd_init()
442
+
443
+ assert result == 0
444
+ assert (tmp_path / "config.yaml").read_text() == "config-template"
445
+ assert (tmp_path / "review_prompt.md").read_text() == "existing-prompt"
446
+
447
+
448
+ def test_cmd_init_returns_error_when_template_missing(mocker, tmp_path) -> None:
449
+ """It should return 1 when the bundled config template cannot be found."""
450
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
451
+
452
+ def _raise(*args: object, **kwargs: object) -> None:
453
+ raise FileNotFoundError("missing")
454
+
455
+ mocker.patch("src.ai_review.importlib.resources.files", side_effect=_raise)
456
+ mocker.patch("builtins.print")
457
+
458
+ result = ai_review.cmd_init()
459
+
460
+ assert result == 1
461
+
462
+
463
+ def test_cmd_init_returns_error_when_prompt_template_missing(mocker, tmp_path) -> None:
464
+ """It should return 1 when the review_prompt.md template cannot be found.
465
+
466
+ config.yaml is already written at that point; the function still surfaces the error.
467
+ """
468
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
469
+
470
+ class _ConfigOnlyResources(_FakeResource):
471
+ def __init__(self) -> None:
472
+ super().__init__("")
473
+
474
+ def joinpath(self, name: str) -> "_FakeResource":
475
+ if name == "config.yaml.template":
476
+ return _FakeResource("config-template")
477
+ raise FileNotFoundError(name)
478
+
479
+ mocker.patch(
480
+ "src.ai_review.importlib.resources.files",
481
+ return_value=_ConfigOnlyResources(),
482
+ )
483
+ mocker.patch("builtins.print")
484
+
485
+ result = ai_review.cmd_init()
486
+
487
+ assert result == 1
488
+ # config.yaml was already written before the error
489
+ assert (tmp_path / "config.yaml").read_text() == "config-template"
490
+ assert not (tmp_path / "review_prompt.md").exists()
491
+
492
+
493
+ def test_cmd_init_overwrites_both_files_when_user_accepts(mocker, tmp_path) -> None:
494
+ """It should overwrite both existing files when the user confirms both prompts."""
495
+ (tmp_path / "config.yaml").write_text("old-config")
496
+ (tmp_path / "review_prompt.md").write_text("old-prompt")
497
+ mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
498
+ mocker.patch(
499
+ "src.ai_review.importlib.resources.files",
500
+ side_effect=_fake_pkg_resources,
501
+ )
502
+ mocker.patch("builtins.input", return_value="y")
503
+ mocker.patch("builtins.print")
504
+
505
+ result = ai_review.cmd_init()
506
+
507
+ assert result == 0
508
+ assert (tmp_path / "config.yaml").read_text() == "config-template"
509
+ assert (tmp_path / "review_prompt.md").read_text() == "prompt-template"
510
+
511
+
512
+ def test_main_dispatches_to_cmd_init(mocker) -> None:
513
+ """It should call cmd_init when the init subcommand is provided."""
514
+ mocker.patch("src.ai_review.sys.argv", ["ai_review.py", "init"])
515
+ cmd_init_mock = mocker.patch("src.ai_review.cmd_init", return_value=0)
516
+
517
+ result = ai_review.main()
518
+
519
+ assert result == 0
520
+ cmd_init_mock.assert_called_once_with()
521
+
522
+
523
+ # ---------------------------------------------------------------------------
524
+ # Helpers for cmd_init tests
525
+ # ---------------------------------------------------------------------------
526
+
527
+ class _FakeResource:
528
+ """Minimal stand-in for an importlib.resources path object."""
529
+
530
+ def __init__(self, text: str) -> None:
531
+ self._text = text
532
+
533
+ def joinpath(self, name: str) -> "_FakeResource":
534
+ return self
535
+
536
+ def read_text(self, encoding: str = "utf-8") -> str:
537
+ return self._text
538
+
539
+
540
+ def _fake_pkg_resources(package: str) -> _FakeResource:
541
+ """Return a fake resource root whose joinpath distinguishes template names."""
542
+
543
+ class _Dispatcher(_FakeResource):
544
+ def __init__(self) -> None:
545
+ super().__init__("")
546
+
547
+ def joinpath(self, name: str) -> _FakeResource:
548
+ if name == "config.yaml.template":
549
+ return _FakeResource("config-template")
550
+ if name == "review_prompt.md.template":
551
+ return _FakeResource("prompt-template")
552
+ raise FileNotFoundError(name)
553
+
554
+ return _Dispatcher()