semantic-diff 0.1.0__tar.gz → 0.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 (63) hide show
  1. semantic_diff-0.3.0/LICENSE +21 -0
  2. semantic_diff-0.3.0/PKG-INFO +269 -0
  3. semantic_diff-0.3.0/README.md +232 -0
  4. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/pyproject.toml +21 -3
  5. semantic_diff-0.3.0/semantic_diff/analyzers/llm_analyzer.py +312 -0
  6. semantic_diff-0.3.0/semantic_diff/change_set.py +49 -0
  7. semantic_diff-0.3.0/semantic_diff/cli.py +469 -0
  8. semantic_diff-0.3.0/semantic_diff/diff_pack.py +156 -0
  9. semantic_diff-0.3.0/semantic_diff/formatters/console_formatter.py +300 -0
  10. semantic_diff-0.3.0/semantic_diff/formatters/markdown_formatter.py +215 -0
  11. semantic_diff-0.3.0/semantic_diff/gitlab_env.py +34 -0
  12. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff/models.py +60 -9
  13. semantic_diff-0.3.0/semantic_diff/parsers/git_parser.py +229 -0
  14. semantic_diff-0.3.0/semantic_diff/prompt_parts.py +114 -0
  15. semantic_diff-0.3.0/semantic_diff/providers/__init__.py +55 -0
  16. semantic_diff-0.3.0/semantic_diff/providers/anthropic_provider.py +48 -0
  17. semantic_diff-0.3.0/semantic_diff/providers/base.py +121 -0
  18. semantic_diff-0.3.0/semantic_diff/providers/factory.py +70 -0
  19. semantic_diff-0.3.0/semantic_diff/providers/openai_compat.py +176 -0
  20. semantic_diff-0.3.0/semantic_diff/providers/retrying.py +103 -0
  21. semantic_diff-0.3.0/semantic_diff/review/__init__.py +4 -0
  22. semantic_diff-0.3.0/semantic_diff/review/agent.py +313 -0
  23. semantic_diff-0.3.0/semantic_diff/review/markdown.py +124 -0
  24. semantic_diff-0.3.0/semantic_diff/review/report.py +70 -0
  25. semantic_diff-0.3.0/semantic_diff/review/tools.py +310 -0
  26. semantic_diff-0.3.0/semantic_diff.egg-info/PKG-INFO +269 -0
  27. semantic_diff-0.3.0/semantic_diff.egg-info/SOURCES.txt +51 -0
  28. semantic_diff-0.3.0/semantic_diff.egg-info/entry_points.txt +2 -0
  29. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff.egg-info/requires.txt +9 -1
  30. semantic_diff-0.3.0/tests/test_action.py +141 -0
  31. semantic_diff-0.3.0/tests/test_change_set.py +158 -0
  32. semantic_diff-0.3.0/tests/test_cli.py +391 -0
  33. semantic_diff-0.3.0/tests/test_cli_mr.py +353 -0
  34. semantic_diff-0.3.0/tests/test_cli_review.py +174 -0
  35. semantic_diff-0.3.0/tests/test_converse.py +398 -0
  36. semantic_diff-0.3.0/tests/test_diff_pack.py +294 -0
  37. semantic_diff-0.3.0/tests/test_formatters.py +585 -0
  38. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/tests/test_git_parser.py +367 -339
  39. semantic_diff-0.3.0/tests/test_git_parser_range.py +203 -0
  40. semantic_diff-0.3.0/tests/test_llm_analyzer.py +549 -0
  41. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/tests/test_models.py +55 -47
  42. semantic_diff-0.3.0/tests/test_prompt_parts.py +102 -0
  43. semantic_diff-0.3.0/tests/test_providers.py +622 -0
  44. semantic_diff-0.3.0/tests/test_review_agent.py +669 -0
  45. semantic_diff-0.3.0/tests/test_review_markdown.py +306 -0
  46. semantic_diff-0.3.0/tests/test_review_tools.py +475 -0
  47. semantic_diff-0.1.0/PKG-INFO +0 -131
  48. semantic_diff-0.1.0/README.md +0 -103
  49. semantic_diff-0.1.0/semantic_diff/analyzers/llm_analyzer.py +0 -413
  50. semantic_diff-0.1.0/semantic_diff/cli.py +0 -86
  51. semantic_diff-0.1.0/semantic_diff/formatters/console_formatter.py +0 -165
  52. semantic_diff-0.1.0/semantic_diff/parsers/git_parser.py +0 -208
  53. semantic_diff-0.1.0/semantic_diff.egg-info/PKG-INFO +0 -131
  54. semantic_diff-0.1.0/semantic_diff.egg-info/SOURCES.txt +0 -20
  55. semantic_diff-0.1.0/semantic_diff.egg-info/entry_points.txt +0 -2
  56. semantic_diff-0.1.0/tests/test_llm_analyzer.py +0 -584
  57. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff/__init__.py +0 -0
  58. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff/analyzers/__init__.py +0 -0
  59. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff/formatters/__init__.py +0 -0
  60. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff/parsers/__init__.py +0 -0
  61. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff.egg-info/dependency_links.txt +0 -0
  62. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/semantic_diff.egg-info/top_level.txt +0 -0
  63. {semantic_diff-0.1.0 → semantic_diff-0.3.0}/setup.cfg +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kenaz GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,269 @@
1
+ Metadata-Version: 2.4
2
+ Name: semantic-diff
3
+ Version: 0.3.0
4
+ Summary: AI-powered semantic analysis of git commits
5
+ Author-email: Kenaz GmbH <hello@kenaz.ai>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/tkenaz/semantic_diff
8
+ Project-URL: Repository, https://github.com/tkenaz/semantic_diff
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: anthropic>=0.40.0
19
+ Requires-Dist: click>=8.1.0
20
+ Requires-Dist: rich>=13.0.0
21
+ Requires-Dist: python-dotenv>=1.0.0
22
+ Requires-Dist: gitpython>=3.1.58
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Provides-Extra: openai
25
+ Requires-Dist: openai>=1.40.0; extra == "openai"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
29
+ Requires-Dist: black>=23.0.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
31
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
32
+ Requires-Dist: openai>=1.40.0; extra == "dev"
33
+ Requires-Dist: mutmut>=3.0.0; extra == "dev"
34
+ Requires-Dist: pyyaml; extra == "dev"
35
+ Requires-Dist: httpx; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # semantic-diff
39
+
40
+ [![PyPI version](https://badge.fury.io/py/semantic-diff.svg)](https://pypi.org/project/semantic-diff/)
41
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
42
+
43
+ AI-powered semantic analysis of git commits. Goes beyond `git diff` to show **intent**, **impact**, **risk**, and **review questions**.
44
+
45
+ ## What it does
46
+
47
+ Regular `git diff` shows *what* changed. `semantic-diff` shows:
48
+
49
+ | | git diff | semantic-diff |
50
+ |---|---|---|
51
+ | **What** | Lines added/removed | Same |
52
+ | **Why** | - | Intent behind the change |
53
+ | **Risk** | - | What could break, edge cases |
54
+ | **Impact** | - | Direct and indirect effects |
55
+ | **Review** | - | Questions to ask the author |
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install semantic-diff
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ # Set your API key
67
+ export ANTHROPIC_API_KEY=sk-ant-...
68
+
69
+ # Analyze a commit
70
+ semantic-diff HEAD
71
+
72
+ # Enable automatic analysis before every push
73
+ semantic-diff init
74
+ ```
75
+
76
+ That's it! Now every `git push` will automatically analyze your commits and save reports.
77
+
78
+ ## How It Works
79
+
80
+ ### Manual Analysis
81
+
82
+ ```bash
83
+ # Analyze HEAD commit
84
+ semantic-diff
85
+
86
+ # Analyze specific commit
87
+ semantic-diff abc123
88
+
89
+ # Save report to file
90
+ semantic-diff HEAD --save
91
+
92
+ # Output as JSON
93
+ semantic-diff HEAD --json
94
+ ```
95
+
96
+ ### Automatic Analysis (Pre-Push Hook)
97
+
98
+ ```bash
99
+ # Install the hook (once per project)
100
+ semantic-diff init
101
+
102
+ # Now every push triggers analysis automatically
103
+ git push # → runs semantic-diff, saves report, then pushes
104
+ ```
105
+
106
+ ### Reports
107
+
108
+ Reports are saved to `semantic_diff_reports/` in your project root:
109
+
110
+ ```
111
+ my-project/
112
+ ├── semantic_diff_reports/
113
+ │ ├── abc12345_20240115_143022.md
114
+ │ ├── def67890_20240115_152341.md
115
+ │ └── ...
116
+ ├── src/
117
+ └── ...
118
+ ```
119
+
120
+ Each report includes:
121
+ - Commit metadata
122
+ - Intent analysis with confidence score
123
+ - Impact map (direct and indirect effects)
124
+ - Risk assessment with mitigations
125
+ - Review questions prioritized by importance
126
+
127
+ ### GitHub Action
128
+
129
+ Add to your workflow to analyze PRs automatically:
130
+
131
+ ```yaml
132
+ # .github/workflows/semantic-diff.yml
133
+ name: Semantic Diff
134
+
135
+ on: [pull_request]
136
+
137
+ jobs:
138
+ analyze:
139
+ runs-on: ubuntu-latest
140
+ steps:
141
+ - uses: actions/checkout@v4
142
+ with:
143
+ fetch-depth: 0
144
+
145
+ - uses: tkenaz/semantic_diff@v0.3.0
146
+ with:
147
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
148
+ comment_on_pr: true
149
+ fail_on_risk: high # optional: block merge on high risk
150
+ ```
151
+
152
+ ## Example Output
153
+
154
+ ### Analysis Overview
155
+
156
+ ![Example Output](assets/example-output.png)
157
+
158
+ *Intent analysis with 98% confidence, risk assessment, and review questions*
159
+
160
+ ### What It Finds
161
+
162
+ ![Risk Assessment](assets/risk-assessment.png)
163
+
164
+ *Real example: semantic-diff analyzing itself found XSS vulnerabilities, CI issues, and security misconfigurations*
165
+
166
+ ## Configuration
167
+
168
+ Create a `.env` file in your project or set environment variables:
169
+
170
+ ```bash
171
+ # Required
172
+ ANTHROPIC_API_KEY=sk-ant-...
173
+
174
+ # Optional
175
+ SEMANTIC_DIFF_MODEL=claude-sonnet-5-5 # or claude-opus-5-5
176
+ ```
177
+
178
+ ### OpenAI-compatible gateways
179
+
180
+ Any gateway that speaks the OpenAI Chat Completions protocol (LiteLLM, vLLM,
181
+ corporate LLM hubs, OpenAI itself) works through the `openai` provider:
182
+
183
+ ```bash
184
+ pip install 'semantic-diff[openai]'
185
+
186
+ SEMANTIC_DIFF_PROVIDER=openai
187
+ SEMANTIC_DIFF_BASE_URL=https://your-gateway.example/v1
188
+ SEMANTIC_DIFF_API_KEY=...
189
+ SEMANTIC_DIFF_MODEL=claude-sonnet-4.6 # required: model ids differ per gateway
190
+ ```
191
+
192
+ Retries (rate limits honour `Retry-After`, timeouts, 5xx) are handled once for
193
+ all providers: `SEMANTIC_DIFF_MAX_RETRIES` (attempts, default 3) and
194
+ `SEMANTIC_DIFF_MAX_WAIT` (seconds, default 30).
195
+
196
+ ### Diff budget
197
+
198
+ Large changes are not cut blindly. Diffs are packed into a token budget
199
+ (`--max-diff-tokens` / `SEMANTIC_DIFF_MAX_DIFF_TOKENS`, default 60,000):
200
+ code first, then migrations, CI/infra, tests, docs. A file that does not fit
201
+ whole is trimmed at hunk boundaries, never mid-line. Lock files, generated
202
+ output and binaries are listed but never shown. The model is told which files
203
+ it did not see, and every report states the coverage, e.g.
204
+ `Diff coverage: 87% of changed lines` plus the trimmed/not-shown files.
205
+
206
+ ### Agentic review
207
+
208
+ `semantic-diff review` goes further than `mr`: instead of one call over the
209
+ diff, an agent reads around the change - whole functions, callers, the file
210
+ before the change, history - with read-only tools, and submits findings tied
211
+ to lines.
212
+
213
+ ```bash
214
+ semantic-diff review --base origin/dev --save
215
+ semantic-diff review --gitlab-env --json # inside a GitLab MR pipeline
216
+ ```
217
+
218
+ - Tools read git objects at the merge request's head and base, never the
219
+ working tree: uncommitted files are invisible to the model.
220
+ - Every review is bounded: `--max-turns` (`SEMANTIC_DIFF_MAX_TURNS`, default
221
+ 25), `--max-input-tokens` (`SEMANTIC_DIFF_MAX_INPUT_TOKENS`, default
222
+ 1,000,000, cached tokens included) and the diff shown up front
223
+ (`--max-diff-tokens` / `SEMANTIC_DIFF_REVIEW_DIFF_TOKENS`, default 30,000).
224
+ When a limit is reached the model gets one last turn to submit what it has,
225
+ and the report says which limit cut the review short.
226
+ - Each finding is checked in code: does the cited line exist (after the
227
+ change, or only before it), and did the model actually see the file. The
228
+ report flags findings that fail either check.
229
+ - Needs a provider with tool calling: `SEMANTIC_DIFF_PROVIDER=openai`
230
+ (any OpenAI-compatible gateway). Prompt caching is used where the gateway
231
+ supports it, so each turn re-reads the conversation from cache.
232
+
233
+ ## Commands
234
+
235
+ | Command | Description |
236
+ |---------|-------------|
237
+ | `semantic-diff` | Analyze HEAD commit |
238
+ | `semantic-diff <hash>` | Analyze specific commit |
239
+ | `semantic-diff --save` | Save report to `semantic_diff_reports/` |
240
+ | `semantic-diff --json` | Output as JSON |
241
+ | `semantic-diff mr --base origin/main` | Analyze a whole merge request (merge-base..HEAD) |
242
+ | `semantic-diff mr --gitlab-env` | Same, inside a GitLab MR pipeline (reads `CI_MERGE_REQUEST_*`) |
243
+ | `--max-diff-tokens N` | Diff budget for the prompt (default 60000) |
244
+ | `--max-output-tokens N` | Room for the model's answer (default 32000; env `SEMANTIC_DIFF_MAX_OUTPUT_TOKENS`) |
245
+ | `semantic-diff review --base origin/main` | Agentic review of a merge request (see above) |
246
+ | `semantic-diff init` | Install pre-push hook |
247
+ | `semantic-diff uninstall` | Remove pre-push hook |
248
+
249
+ ## Development
250
+
251
+ ```bash
252
+ git clone https://github.com/tkenaz/semantic_diff.git
253
+ cd semantic_diff
254
+ pip install -e ".[dev]"
255
+ pytest
256
+ ```
257
+
258
+ ## Support
259
+
260
+ - **Bug reports & features**: [GitHub Issues](https://github.com/tkenaz/semantic_diff/issues)
261
+ - **Custom integrations or enterprise**: [hello@kenaz.ai](mailto:hello@kenaz.ai)
262
+
263
+ ## License
264
+
265
+ MIT — [Kenaz GmbH](https://kenaz.ai)
266
+
267
+ ---
268
+
269
+ *Built with 🖤 by [Kenaz GmbH](https://kenaz.ai) — AI tools for developers*
@@ -0,0 +1,232 @@
1
+ # semantic-diff
2
+
3
+ [![PyPI version](https://badge.fury.io/py/semantic-diff.svg)](https://pypi.org/project/semantic-diff/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ AI-powered semantic analysis of git commits. Goes beyond `git diff` to show **intent**, **impact**, **risk**, and **review questions**.
7
+
8
+ ## What it does
9
+
10
+ Regular `git diff` shows *what* changed. `semantic-diff` shows:
11
+
12
+ | | git diff | semantic-diff |
13
+ |---|---|---|
14
+ | **What** | Lines added/removed | Same |
15
+ | **Why** | - | Intent behind the change |
16
+ | **Risk** | - | What could break, edge cases |
17
+ | **Impact** | - | Direct and indirect effects |
18
+ | **Review** | - | Questions to ask the author |
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install semantic-diff
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ # Set your API key
30
+ export ANTHROPIC_API_KEY=sk-ant-...
31
+
32
+ # Analyze a commit
33
+ semantic-diff HEAD
34
+
35
+ # Enable automatic analysis before every push
36
+ semantic-diff init
37
+ ```
38
+
39
+ That's it! Now every `git push` will automatically analyze your commits and save reports.
40
+
41
+ ## How It Works
42
+
43
+ ### Manual Analysis
44
+
45
+ ```bash
46
+ # Analyze HEAD commit
47
+ semantic-diff
48
+
49
+ # Analyze specific commit
50
+ semantic-diff abc123
51
+
52
+ # Save report to file
53
+ semantic-diff HEAD --save
54
+
55
+ # Output as JSON
56
+ semantic-diff HEAD --json
57
+ ```
58
+
59
+ ### Automatic Analysis (Pre-Push Hook)
60
+
61
+ ```bash
62
+ # Install the hook (once per project)
63
+ semantic-diff init
64
+
65
+ # Now every push triggers analysis automatically
66
+ git push # → runs semantic-diff, saves report, then pushes
67
+ ```
68
+
69
+ ### Reports
70
+
71
+ Reports are saved to `semantic_diff_reports/` in your project root:
72
+
73
+ ```
74
+ my-project/
75
+ ├── semantic_diff_reports/
76
+ │ ├── abc12345_20240115_143022.md
77
+ │ ├── def67890_20240115_152341.md
78
+ │ └── ...
79
+ ├── src/
80
+ └── ...
81
+ ```
82
+
83
+ Each report includes:
84
+ - Commit metadata
85
+ - Intent analysis with confidence score
86
+ - Impact map (direct and indirect effects)
87
+ - Risk assessment with mitigations
88
+ - Review questions prioritized by importance
89
+
90
+ ### GitHub Action
91
+
92
+ Add to your workflow to analyze PRs automatically:
93
+
94
+ ```yaml
95
+ # .github/workflows/semantic-diff.yml
96
+ name: Semantic Diff
97
+
98
+ on: [pull_request]
99
+
100
+ jobs:
101
+ analyze:
102
+ runs-on: ubuntu-latest
103
+ steps:
104
+ - uses: actions/checkout@v4
105
+ with:
106
+ fetch-depth: 0
107
+
108
+ - uses: tkenaz/semantic_diff@v0.3.0
109
+ with:
110
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
111
+ comment_on_pr: true
112
+ fail_on_risk: high # optional: block merge on high risk
113
+ ```
114
+
115
+ ## Example Output
116
+
117
+ ### Analysis Overview
118
+
119
+ ![Example Output](assets/example-output.png)
120
+
121
+ *Intent analysis with 98% confidence, risk assessment, and review questions*
122
+
123
+ ### What It Finds
124
+
125
+ ![Risk Assessment](assets/risk-assessment.png)
126
+
127
+ *Real example: semantic-diff analyzing itself found XSS vulnerabilities, CI issues, and security misconfigurations*
128
+
129
+ ## Configuration
130
+
131
+ Create a `.env` file in your project or set environment variables:
132
+
133
+ ```bash
134
+ # Required
135
+ ANTHROPIC_API_KEY=sk-ant-...
136
+
137
+ # Optional
138
+ SEMANTIC_DIFF_MODEL=claude-sonnet-5-5 # or claude-opus-5-5
139
+ ```
140
+
141
+ ### OpenAI-compatible gateways
142
+
143
+ Any gateway that speaks the OpenAI Chat Completions protocol (LiteLLM, vLLM,
144
+ corporate LLM hubs, OpenAI itself) works through the `openai` provider:
145
+
146
+ ```bash
147
+ pip install 'semantic-diff[openai]'
148
+
149
+ SEMANTIC_DIFF_PROVIDER=openai
150
+ SEMANTIC_DIFF_BASE_URL=https://your-gateway.example/v1
151
+ SEMANTIC_DIFF_API_KEY=...
152
+ SEMANTIC_DIFF_MODEL=claude-sonnet-4.6 # required: model ids differ per gateway
153
+ ```
154
+
155
+ Retries (rate limits honour `Retry-After`, timeouts, 5xx) are handled once for
156
+ all providers: `SEMANTIC_DIFF_MAX_RETRIES` (attempts, default 3) and
157
+ `SEMANTIC_DIFF_MAX_WAIT` (seconds, default 30).
158
+
159
+ ### Diff budget
160
+
161
+ Large changes are not cut blindly. Diffs are packed into a token budget
162
+ (`--max-diff-tokens` / `SEMANTIC_DIFF_MAX_DIFF_TOKENS`, default 60,000):
163
+ code first, then migrations, CI/infra, tests, docs. A file that does not fit
164
+ whole is trimmed at hunk boundaries, never mid-line. Lock files, generated
165
+ output and binaries are listed but never shown. The model is told which files
166
+ it did not see, and every report states the coverage, e.g.
167
+ `Diff coverage: 87% of changed lines` plus the trimmed/not-shown files.
168
+
169
+ ### Agentic review
170
+
171
+ `semantic-diff review` goes further than `mr`: instead of one call over the
172
+ diff, an agent reads around the change - whole functions, callers, the file
173
+ before the change, history - with read-only tools, and submits findings tied
174
+ to lines.
175
+
176
+ ```bash
177
+ semantic-diff review --base origin/dev --save
178
+ semantic-diff review --gitlab-env --json # inside a GitLab MR pipeline
179
+ ```
180
+
181
+ - Tools read git objects at the merge request's head and base, never the
182
+ working tree: uncommitted files are invisible to the model.
183
+ - Every review is bounded: `--max-turns` (`SEMANTIC_DIFF_MAX_TURNS`, default
184
+ 25), `--max-input-tokens` (`SEMANTIC_DIFF_MAX_INPUT_TOKENS`, default
185
+ 1,000,000, cached tokens included) and the diff shown up front
186
+ (`--max-diff-tokens` / `SEMANTIC_DIFF_REVIEW_DIFF_TOKENS`, default 30,000).
187
+ When a limit is reached the model gets one last turn to submit what it has,
188
+ and the report says which limit cut the review short.
189
+ - Each finding is checked in code: does the cited line exist (after the
190
+ change, or only before it), and did the model actually see the file. The
191
+ report flags findings that fail either check.
192
+ - Needs a provider with tool calling: `SEMANTIC_DIFF_PROVIDER=openai`
193
+ (any OpenAI-compatible gateway). Prompt caching is used where the gateway
194
+ supports it, so each turn re-reads the conversation from cache.
195
+
196
+ ## Commands
197
+
198
+ | Command | Description |
199
+ |---------|-------------|
200
+ | `semantic-diff` | Analyze HEAD commit |
201
+ | `semantic-diff <hash>` | Analyze specific commit |
202
+ | `semantic-diff --save` | Save report to `semantic_diff_reports/` |
203
+ | `semantic-diff --json` | Output as JSON |
204
+ | `semantic-diff mr --base origin/main` | Analyze a whole merge request (merge-base..HEAD) |
205
+ | `semantic-diff mr --gitlab-env` | Same, inside a GitLab MR pipeline (reads `CI_MERGE_REQUEST_*`) |
206
+ | `--max-diff-tokens N` | Diff budget for the prompt (default 60000) |
207
+ | `--max-output-tokens N` | Room for the model's answer (default 32000; env `SEMANTIC_DIFF_MAX_OUTPUT_TOKENS`) |
208
+ | `semantic-diff review --base origin/main` | Agentic review of a merge request (see above) |
209
+ | `semantic-diff init` | Install pre-push hook |
210
+ | `semantic-diff uninstall` | Remove pre-push hook |
211
+
212
+ ## Development
213
+
214
+ ```bash
215
+ git clone https://github.com/tkenaz/semantic_diff.git
216
+ cd semantic_diff
217
+ pip install -e ".[dev]"
218
+ pytest
219
+ ```
220
+
221
+ ## Support
222
+
223
+ - **Bug reports & features**: [GitHub Issues](https://github.com/tkenaz/semantic_diff/issues)
224
+ - **Custom integrations or enterprise**: [hello@kenaz.ai](mailto:hello@kenaz.ai)
225
+
226
+ ## License
227
+
228
+ MIT — [Kenaz GmbH](https://kenaz.ai)
229
+
230
+ ---
231
+
232
+ *Built with 🖤 by [Kenaz GmbH](https://kenaz.ai) — AI tools for developers*
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "semantic-diff"
7
- version = "0.1.0"
7
+ version = "0.3.0"
8
8
  description = "AI-powered semantic analysis of git commits"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -25,20 +25,28 @@ dependencies = [
25
25
  "click>=8.1.0",
26
26
  "rich>=13.0.0",
27
27
  "python-dotenv>=1.0.0",
28
- "gitpython>=3.1.0",
28
+ "gitpython>=3.1.58", # CVE-2026-42215, -44243 and later fixes
29
29
  "pydantic>=2.0.0",
30
30
  ]
31
31
 
32
32
  [project.optional-dependencies]
33
+ openai = [
34
+ "openai>=1.40.0",
35
+ ]
33
36
  dev = [
34
37
  "pytest>=7.0.0",
35
38
  "pytest-cov>=4.0.0",
36
39
  "black>=23.0.0",
37
40
  "ruff>=0.1.0",
41
+ "mypy>=1.0.0",
42
+ "openai>=1.40.0",
43
+ "mutmut>=3.0.0",
44
+ "pyyaml", # tests execute action.yml steps
45
+ "httpx", # tests build SDK errors from real responses; newer SDKs ship httpx2
38
46
  ]
39
47
 
40
48
  [project.scripts]
41
- semantic-diff = "semantic_diff.cli:main"
49
+ semantic-diff = "semantic_diff.cli:cli"
42
50
 
43
51
  [project.urls]
44
52
  Homepage = "https://github.com/tkenaz/semantic_diff"
@@ -53,5 +61,15 @@ target-version = ["py310", "py311", "py312"]
53
61
 
54
62
  [tool.ruff]
55
63
  line-length = 100
64
+
65
+ [tool.ruff.lint]
56
66
  select = ["E", "F", "I", "N", "W"]
57
67
  ignore = ["E501"]
68
+
69
+ [tool.mutmut]
70
+ paths_to_mutate = ["semantic_diff/"]
71
+ tests_dir = ["tests/"]
72
+ also_copy = ["action.yml", "CHANGELOG.md", "pyproject.toml"]
73
+
74
+ [tool.pytest.ini_options]
75
+ testpaths = ["tests"]