gitpr-cli 1.0.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

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 (45) hide show
  1. {gitpr_cli-1.0.0.dist-info → gitpr_cli-1.2.0.dist-info}/METADATA +25 -37
  2. gitpr_cli-1.2.0.dist-info/RECORD +67 -0
  3. src/cache.py +63 -2
  4. src/config.py +336 -1
  5. src/config_schema.py +1046 -0
  6. src/core.py +133 -53
  7. src/diff_parser.py +162 -0
  8. src/doc_links.py +28 -0
  9. src/fix/__init__.py +16 -0
  10. src/fix/apply_fix.py +479 -0
  11. src/fix/fix_history.py +153 -0
  12. src/fix/patch_applier.py +172 -0
  13. src/fix/patch_extractor.py +61 -0
  14. src/fix/patch_provenance.py +96 -0
  15. src/fix/patch_safety_classifier.py +101 -0
  16. src/fix/rollback_fix.py +69 -0
  17. src/i18n.py +18 -3
  18. src/infrastructure/scm/azure_devops_provider.py +13 -0
  19. src/infrastructure/scm/base.py +29 -1
  20. src/infrastructure/scm/bitbucket_provider.py +9 -0
  21. src/infrastructure/scm/github_provider.py +77 -4
  22. src/infrastructure/scm/gitlab_provider.py +50 -3
  23. src/linter_engine.py +11 -2
  24. src/linter_wizard.py +6 -2
  25. src/main.py +518 -82
  26. src/mcp_server.py +270 -0
  27. src/review/__init__.py +13 -0
  28. src/review/diff_normalizer.py +84 -0
  29. src/review/diff_source.py +69 -0
  30. src/review/remote_pr.py +319 -0
  31. src/review/render.py +75 -0
  32. src/reviewer_resolution.py +159 -0
  33. src/reviewer_suggestion.py +19 -3
  34. src/spinner.py +15 -5
  35. src/suggest_reviewers.py +19 -12
  36. src/ui/chat_app.py +3 -31
  37. src/ui/config_app.py +1835 -0
  38. src/ui/pr_publish_app.py +222 -38
  39. src/updater.py +145 -200
  40. src/usage_log.py +175 -0
  41. gitpr_cli-1.0.0.dist-info/RECORD +0 -49
  42. {gitpr_cli-1.0.0.dist-info → gitpr_cli-1.2.0.dist-info}/WHEEL +0 -0
  43. {gitpr_cli-1.0.0.dist-info → gitpr_cli-1.2.0.dist-info}/entry_points.txt +0 -0
  44. {gitpr_cli-1.0.0.dist-info → gitpr_cli-1.2.0.dist-info}/licenses/LICENSE +0 -0
  45. {gitpr_cli-1.0.0.dist-info → gitpr_cli-1.2.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpr-cli
3
- Version: 1.0.0
3
+ Version: 1.2.0
4
4
  Summary: AI-powered PR automation, commit messages, and code review (Gemini, DeepSeek, and Ollama)
5
5
  Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
6
  Requires-Python: >=3.10
@@ -66,27 +66,6 @@ This project was developed in Python and uses the following main libraries:
66
66
  * [**Requests**](https://pypi.org/project/requests/): Elegant and robust library for HTTP requests, used to communicate with the GitHub REST API.
67
67
  * [**MCP**](https://pypi.org/project/mcp/): Official Python SDK for the Model Context Protocol, enabling GitPR to integrate directly with AI-powered editors and IDEs.
68
68
 
69
- ----
70
-
71
- ## 📦 How to Compile the Executable Locally
72
-
73
- If you want to generate your own binary from the source code, we use **PyInstaller**. Make sure you are in the project root directory with the virtual environment configured.
74
-
75
- 1. Install development dependencies (if you haven't already):
76
- ```bash
77
- pipenv install --dev
78
- ```
79
-
80
- 2. Run the build command pointing to our entry point (`run.py`):
81
- ```bash
82
- pipenv run pyinstaller --noconfirm --onefile --icon=icon.ico --name gitpr run.py
83
- ```
84
- > **Technical note:** The `--onefile` flag ensures all Python, libraries, and dependencies are compressed into a single binary, while `--paths src` helps the compiler find our `core.py` and `config.py` files. 🛠️
85
-
86
- After running this command, PyInstaller will create some folders (`build` and `dist`).
87
- Your final ready-to-use file will be inside the **`dist/`** folder named `gitpr` (or `gitpr.exe` on Windows).
88
-
89
-
90
69
  ----
91
70
 
92
71
  ## 🧪 Running Tests
@@ -107,11 +86,13 @@ Pytest will automatically detect files inside the `tests/` folder and display a
107
86
  ----
108
87
  ## **⚙️ Installation and Configuration**
109
88
 
110
- ### **Using the Executable (Recommended)**
89
+ ### **Installing from PyPI (Recommended)**
111
90
 
112
- 1. Download the gitpr executable file from the "Releases" tab on GitHub.
113
- 2. Move the executable to a folder that is in your PATH (e.g.: /usr/local/bin on Linux/Mac or your user folder on Windows).
114
- 3. On the first run, the wizard will guide you:
91
+ 1. Install the package with pip:
92
+ ```bash
93
+ pip install gitpr-cli
94
+ ```
95
+ 2. On the first run, the wizard will guide you:
115
96
  ```bash
116
97
  $ gitpr
117
98
  ```
@@ -126,6 +107,8 @@ Pytest will automatically detect files inside the `tests/` folder and display a
126
107
  ```
127
108
  *Note: Your configuration will be securely saved in the `~/.gitpr/.env` file.*
128
109
 
110
+ *Note (updates): GitPR is distributed exclusively through PyPI. On every run it checks whether a newer version has been published, and when one exists it **blocks the execution** and asks you to run `pip install --upgrade gitpr-cli`. See [auto-update.md](docs/auto-update.md).*
111
+
129
112
  > **🔒 Security Note:** GitPR CLI uses symmetric encryption (Fernet). Your API key is stored as a hash in the `.env` file, and the master key for decryption is automatically generated in `~/.gitpr/secret.key`. **Never share your secret.key file.**
130
113
 
131
114
  ### From Source Code
@@ -165,18 +148,18 @@ You can pass the following *flags* for specific actions:
165
148
  * `--status`: Lists uncommitted file changes categorized as **new**, **modified**, and **deleted** — fast, no AI, no network. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/git-status.md)
166
149
  * `--no-unstaged-check`: Skips the unstaged files verification before AI processing for a single invocation. Equivalent to `GITPR_SKIP_UNSTAGED_CHECK=true` for one run. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/git-status.md)
167
150
  * `--linter-setup`: **Interactive external linter wizard.** Guides you through installing and configuring external linters (ESLint, PHPCS, Stylelint) as a Checkstyle XML bridge. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/linter-regras-customizadas.md)
168
- * `--mcp`: Starts GitPR as an **MCP server** (Model Context Protocol) on stdio transport. Enables integration with VS Code, Cursor, Claude Desktop, and other MCP-compatible editors — exposing all GitPR AI capabilities as 12 annotated tools, 15 resources, and 7 pre-built prompts directly inside your IDE. Also available as the standalone `gitpr-mcp` command.
151
+ * `--mcp`: Starts GitPR as an **MCP server** (Model Context Protocol) on stdio transport. Enables integration with VS Code, Cursor, Claude Desktop, and other MCP-compatible editors — exposing all GitPR AI capabilities as 14 annotated tools, 18 resources, and 7 pre-built prompts directly inside your IDE. Also available as the standalone `gitpr-mcp` command.
169
152
  * `--plugins`: Lists all **globally installed plugins** — custom linter packs from `~/.gitpr/plugins/linter/` and MCP prompt templates from `~/.gitpr/plugins/prompts/`. These plugins apply across all your projects without duplication. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/plugins-system.md)
170
153
  * `--install`: **Interactive Setup Wizard.** Runs a guided 4-step setup: downloads skill templates, installs Git hooks, configures MCP for detected editors, and checks/requests your AI provider API key. Each step asks for confirmation before proceeding.
171
154
  * `-ih` or `--installhooks`: Automatically installs **local Git Hooks** (`pre-commit` and `prepare-commit-msg`) in your repository.
172
- * `-s` or `--skill`: Creates the AI context template files (`.gitpr.commit.md`, `.gitpr.pr.md`, `.gitpr.review.md`, `.gitpr.filereview.md`, `.gitpr.issue.md`, `.gitpr.blame.md`) and the Linter (`.gitpr.linter.yml`) at the project root.
155
+ * `-s` or `--skill`: Creates the AI context template files (`.gitpr.commit.md`, `.gitpr.pr.md`, `.gitpr.review.md`, `.gitpr.filereview.md`, `.gitpr.issue.md`, `.gitpr.blame.md`) and the Linter (`.gitpr.linter.yml`) inside `.gitpr/skill/`.
173
156
  * `-is` or `--issue`: Automatically generates a draft of a **standardized Issue** and opens an interactive interface (TUI) for editing or direct submission via REST API. This feature has **3 context engines** depending on the command combination:
174
157
  * **New Code Issue (`gitpr -is`):** Reads the current `git diff`. **Why use:** Ideal for quickly documenting the task you just finished programming, before committing.
175
158
  * **Epic/Release Issue (`gitpr -is -ht`):** Reads the full history of the current branch (Git Log + PR Cache). **Why use:** Ideal for generating consolidated documentation of an entire release or a large *feature* that took several days/commits to complete.
176
159
  * **Archaeological/Technical Debt Issue (`gitpr -is -b file:lines`):** Reads the timeline of a specific business rule. **Why use:** Ideal for documenting technical debt, explaining how a legacy code block evolved and why it needs to be refactored.
177
160
  * **PR Publisher (default):** Running `gitpr` generates the PR description with AI, saves the `.md` file to `.gitpr/reports/pr_desc/`, and opens an interactive terminal interface (TUI) to review, edit, and publish the Pull Request directly to GitHub via REST API. Before generation, it checks for unstaged files and offers a modal to manage them. Use `--no-publish` to save only the PR file locally without opening the publisher, or `--no-edit` to auto-commit pending changes (with lint validation), auto-push, and publish immediately — handling existing PR updates, optional auto-merge, and clear error feedback when merge conflicts occur. Use `--base <branch>` to change the target branch. 📖 [Full docs](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pull-request-publication.md)
178
161
  * `-h` or `--help`: Shows the general help with all options. Use together with another flag for **contextual help** (e.g.: `gitpr -h --issue`, `gitpr -h --linter`) with a direct link to the detailed documentation of each feature.
179
- * `-u` or `--update`: Checks and installs the latest version of GitPR (Auto-Updater).
162
+ * `-u` or `--update`: Checks the latest version of GitPR on PyPI and shows how to update it (Auto-Updater).
180
163
 
181
164
  > **⚙️ Technical Note (--hook):** GitPR has a hidden flag `--hook <file>` that is triggered exclusively by the Git Hooks system in the background. It allows the AI to inject the suggested message directly into Git's temporary file, without cluttering your terminal.
182
165
  >
@@ -246,7 +229,7 @@ You can dynamically switch models by configuring the `GEMINI_API_MODEL_PRIMARY`
246
229
 
247
230
  ## 🎯 Customizable "Skills" System (Prompt Engineering)
248
231
 
249
- Instead of hiding AI instructions in the source code, GitPR uses local Markdown files that act as *System Instructions*. When running `gitpr -s`, the following files are generated at the root of your project to customize the AI's "persona" according to your company's business rules:
232
+ Instead of hiding AI instructions in the source code, GitPR uses local Markdown files that act as *System Instructions*. When running `gitpr -s`, the following files are generated inside `.gitpr/skill/` to customize the AI's "persona" according to your company's business rules:
250
233
 
251
234
  * `.gitpr.commit.md`: Rules for generating short commit messages.
252
235
  * `.gitpr.pr.md`: Required topic structure for the Pull Request description.
@@ -275,8 +258,8 @@ To force a specific language, set `GITPR_LANG=pt_br` or `GITPR_LANG=en` in `~/.g
275
258
  GitPR includes an automatic versioning system for Git hook scripts (`pre-commit`, `prepare-commit-msg`, `pre-push`, `post-checkout`, `post-merge`). Every time you run `gitpr`, the system silently checks whether your installed hooks match the latest version and automatically updates them if needed — all while respecting your language preference.
276
259
 
277
260
  **How it works:**
278
- 1. Reads `SCRIPTS_VERSION` and `SCRIPTS_LANG` from `~/.gitpr/.env`
279
- 2. Compares with the latest version (`__scripts_version__`) shipped with your GitPR release
261
+ 1. Reads `SCRIPTS_VERSION` and `SCRIPTS_INSTALLED_LANG` from `~/.gitpr/.env`
262
+ 2. Compares with the latest version (`__scripts_version__`) shipped with your GitPR release, and with the language you asked for (`SCRIPTS_LANG`, empty = follow the interface language)
280
263
  3. If versions or language differ → automatically downloads and updates hooks
281
264
  4. If everything matches → skips entirely (single `.env` read, zero network I/O)
282
265
 
@@ -352,6 +335,8 @@ Once configured, use natural language in your editor's AI chat:
352
335
  | `generate_issue` | Structured issue from diff, history, or blame |
353
336
  | `list_unstaged_files` | Uncommitted file changes categorized (new/modified/deleted) |
354
337
  | `analyze_unstaged_diff` | Unstaged diff only (working tree vs index) |
338
+ | `list_fix_candidates` | Fix candidates of the last review: patch, classification, id (read-only) |
339
+ | `review_remote_pr` | AI review of a pull request already open on the forge, fetched by number (read-only) |
355
340
 
356
341
  ### Direct CLI Invocation
357
342
 
@@ -447,18 +432,20 @@ If you want to implement GitPR as an automated quality barrier in your team, che
447
432
 
448
433
  * [**Pull Request (Default Mode)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pr-descricao-padrao.md) — Complete flow for generating PR descriptions without flags.
449
434
  * [**Pull Request Publisher TUI**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/pull-request-publication.md) — How to review and publish Pull Requests directly to GitHub from the terminal.
450
- * [**AI Code Review**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/code-review-ia.md) — Guide to review modes (`--review`, `--fullreview`) and file auditing (`--input`).
435
+ * [**AI Code Review**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/code-review-ia.md) — Guide to review modes (`--review`, `--fullreview`), file auditing (`--input`) and remote pull request review (`gitpr review-pr`).
436
+ * [**Remote Pull Request Review (gitpr review-pr)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/review-pr.md) — How the `gitpr review-pr` subcommand reviews a pull request that is already open on the forge, fetching its diff from the API without checking out its branch.
451
437
  * [**AI Commit Messages**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/commit-message-ia.md) — How to generate messages in the Conventional Commits standard and integrate with Git Hooks.
452
438
  * [**Issue Generation and TUI Interface**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/issue-tui-help.md) — How to use the terminal graphical interface (TUI) and the 3 context engines to manage structured Issues.
453
439
  * [**Code Archaeologist (Git Blame)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/blame-arqueologo.md) — How to trace the origin of business rules with `git blame` and AI.
454
440
  * [**Skills and Templates System**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/skill-template.md) — How to customize AI behavior with `.gitpr.*.md` files.
455
441
  * [**Release Notes & Changelog (gitpr release)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/release-notes.md) — How the `gitpr release` subcommand generates the changelog / release notes of a repository, suggests the next semantic version and publishes releases on the forge.
442
+ * [**Fix Command (gitpr fix)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/fix-command.md) — How the `gitpr fix` subcommand turns the findings of the last review into patches you read before they touch your tree, classifies each one by safety, and undoes an applied patch on demand.
456
443
 
457
444
  ### Configuration & Infrastructure
458
445
 
459
446
  * [**Install Wizard**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/install-wizard.md) — Step-by-step guided setup for configuring GitPR in a new project.
460
447
  * [**AI Providers**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/providers-ia.md) — Configuration and selection between Google Gemini, DeepSeek, and Ollama.
461
- * [**Auto-Updater**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/auto-update.md) — How GitPR's automatic update (hot-swap) works.
448
+ * [**Auto-Updater**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/auto-update.md) — How GitPR's automatic update and the mandatory update block work.
462
449
  * [**Architecture**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/ARCHITECTURE.md) — Project architecture, design patterns, and technical stack overview.
463
450
  * [**GitHub Token (PAT) Integration and Security**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/github-pat-integration.md) — Understand how GitPR creates issues directly in the repository with authentication.
464
451
  * [**Internationalization (i18n)**](https://github.com/gitpr-cli/gitpr.git/blob/main/docs/i18n_explanation.md) — Architecture, usage patterns, and how to add new languages.
@@ -476,9 +463,10 @@ If you run the same command again without changing the code, GitPR intercepts th
476
463
 
477
464
  Never worry about manually downloading new versions again. GitPR has a Connection Guardian and a built-in updater:
478
465
  * It checks network availability before starting so it doesn't block your offline workflow.
479
- * On each execution, it silently checks if there is a new official release on the GitHub API.
480
- * You can force the check and installation by running `gitpr --update` or `gitpr -u`.
481
- * The tool uses the *Hot-Swap* technique, downloading the new `.exe` and transparently replacing the old version.
466
+ * On each execution, it checks PyPI for a newer published version (cached for 24 hours).
467
+ * When a newer version exists, it **blocks the execution** and asks you to run `pip install --upgrade gitpr-cli`.
468
+ * You can force the check at any time with `gitpr --update` or `gitpr -u` — it shows the upgrade command without installing anything.
469
+ * Scripts, Git hooks, the MCP server and the contextual help are never blocked.
482
470
 
483
471
  ## Publishing to PyPI
484
472
 
@@ -0,0 +1,67 @@
1
+ gitpr_cli-1.2.0.dist-info/licenses/LICENSE,sha256=UQzLC6mwqb-ZNDkBBAqOxC-SMQcEID0gaM6oFcu6u48,27030
2
+ src/__init__.py,sha256=WZW9x8P5CYnru29UiarFa8q1nQzuwYWyIodSOlruCWI,29
3
+ src/ai_providers.py,sha256=QyFEOsXyA59lZziO5bl-4nlYFJpxBcxU9aLhcTBnkWE,14633
4
+ src/blame_engine.py,sha256=Zov1hxrt7Dcmf56ovJKz3QmHIfzDKtSub2iItXeg9-A,17104
5
+ src/cache.py,sha256=GC2ZT0ThAtH22aRRZapIeauATv_nqBfiRsXjqeMhAiI,6368
6
+ src/changelog_builder.py,sha256=6tqJVHpY4Ta5shOSNWDEo_eHlKmDrU2dUSzS0wyYe10,7116
7
+ src/chat_memory.py,sha256=PcohnyspAfIwwwbsp9U2Wk_1AylJMFEMoWqRSJe_w30,8949
8
+ src/commit_classifier.py,sha256=8_LHQEzisWflV5ZsK31P3fwyu2QWacv8cdFErXYe030,4668
9
+ src/config.py,sha256=9945b0sTM5xL4a81M-CyJ6qfnAQ-Vkf3vr9Old79bjw,33985
10
+ src/config_schema.py,sha256=a7fSsp39h9Pe97uMrUTncuLjGzB8mWvF77vYhJZIcmw,35283
11
+ src/core.py,sha256=zWrz86ifjly5DqoqfQvqdQ0up6yyqFlDYYdB8t8cnyU,76310
12
+ src/diff_parser.py,sha256=62X69ves4tlzNgVKXNsfWdOMwqn2h16RkUOPqszMU7k,11252
13
+ src/doc_links.py,sha256=DuovU-RF9kjbisBdEoGAsuavQ2y0MYDhqy6Sz6vbrGI,1157
14
+ src/github_api.py,sha256=ILm7e03UP80swc3XuJvIJJvhLp81-V_3kQQ1EuAcN8Q,3836
15
+ src/i18n.py,sha256=8s-Bsvp-p3ZZhj0FvDNTRqfWsEio5v4VvXmS1NSqNW8,4578
16
+ src/issue_engine.py,sha256=XwW9C5uX84eOWWZMerm0DvE8LpLRcjhrLsXtt7yftak,10872
17
+ src/linter_engine.py,sha256=8SIs_FUtxEBeTMKWuqatqzlyyToYIjG5xeg0X7FYRAA,12683
18
+ src/linter_wizard.py,sha256=7J_nQFghVwCaKG6QI3K45KcOaxHSH1oTCAvP_6tnCQM,7424
19
+ src/main.py,sha256=B9X4Yr1QZxCioL2dvXOkJ7m37DzOR6DB2E6unLBqHuI,98535
20
+ src/mcp_server.py,sha256=q2clMxTtjLLC-P6Vh4XMq0xylnoUw-K2IFQvgvHIf7o,90479
21
+ src/metrics.py,sha256=VC68t8xGUBFry-ANvEb_TjaRkboPi37__GxK0eHZOe4,21250
22
+ src/net.py,sha256=f0MOkXyIxi4HVetsybtWpV_yHjiC17T2JMWySBdoV2I,2774
23
+ src/release_engine.py,sha256=gwTnOq0ESK26BqsW1RLlysGwL0ZS5guj1qG2V-yUyWI,21610
24
+ src/reviewer_resolution.py,sha256=lZ3csSJHN6Y5TJ3U3p9uuXikOgG7fH4qqx7X9-4F7pc,5754
25
+ src/reviewer_suggestion.py,sha256=jk9FAyp7WkkJbi-yepz7LDF1_tSHxJEEjcajMKF5HdY,8501
26
+ src/security.py,sha256=fkWy-r4tdISH0xOyWZyR8ZCFyLuYqu8fn9sKsIeNAso,1351
27
+ src/spinner.py,sha256=63pEotiDa3TVwBr-sn0MJoDPQ_uWJTTwINXieJIDDKc,8964
28
+ src/suggest_reviewers.py,sha256=-wRe0HYksx4FWQZ-eDvU9Ghdk5gqtEt457KQP7sE31Y,5181
29
+ src/tui_issue.py,sha256=WEFxT4kzWQ_KbSDsOnS_iuYXasZySB-68jryGNm0peg,10331
30
+ src/updater.py,sha256=hm4brG_lSPe82LWFVb41iVMOBYUI824svwsfzMfxxUQ,4771
31
+ src/usage_log.py,sha256=314sTT5Gl_uOXqWSIi-V42bnTHuMSYAZ6G6-_15uEGQ,5968
32
+ src/version_bump.py,sha256=OjqJe9OL1-1dT5od7-SgU5ZN_dTtR_aKX_oSjSY64YQ,2954
33
+ src/fix/__init__.py,sha256=YcN1nGpzWyXczd35LWEXdFpviKKsb9JS8e4bD6KcVcQ,935
34
+ src/fix/apply_fix.py,sha256=yMinMW50Fw62V-k7hRwN1lsikCJbz6xV5iX4IH0sdxY,17912
35
+ src/fix/fix_history.py,sha256=pHXHpt-SstitbLDmlPloDVKlH79FUD8hqKjVK5xKLMA,5626
36
+ src/fix/patch_applier.py,sha256=ahruhdKOhrt2excc3nJljoWi4_0pUj26owSVAQWeeKQ,6258
37
+ src/fix/patch_extractor.py,sha256=gEiwSvxGNHM74TnubTN22NBpbXDwvNpB2vMqgpF7hQQ,2514
38
+ src/fix/patch_provenance.py,sha256=sF934ntcZjJCTzzhtuR2Pi-vMUdXFElKcuw5riwPnUk,3195
39
+ src/fix/patch_safety_classifier.py,sha256=StZvh_0Y-ZCdf_LwFoVAdfhpi0b7v1TOxTRoG86_63M,4121
40
+ src/fix/rollback_fix.py,sha256=rMBYewuvlhJOFdo-Ke_SPfu1O-yd6NJzEYiO5o-LcKk,2501
41
+ src/infrastructure/__init__.py,sha256=zTIcY3cscsdkXogSGXoJbH0mVGFbKYTRK32fg26wr9U,81
42
+ src/infrastructure/scm/__init__.py,sha256=3_4CmrZPZSmDbFwf_0YBeKc935jWV8oAHaZtC_i-Fak,1550
43
+ src/infrastructure/scm/azure_devops_provider.py,sha256=ezRS_O2450mfYEfqFOD4UBSVFhT3aJdx3DEVkZcJjac,14717
44
+ src/infrastructure/scm/base.py,sha256=L-7NYG2hqIWKzKCsQ5NurtgJJvvYvjTVOs0NJ2Aqx_M,9536
45
+ src/infrastructure/scm/bitbucket_provider.py,sha256=jv62MlOd0Iiu3VYAHUffJO2D95TE4k2lmukQL93bOd8,12105
46
+ src/infrastructure/scm/factory.py,sha256=Qeearq8eWnF_4boI68rVBkoGEiS-xRGD4V-O_FF0204,3856
47
+ src/infrastructure/scm/github_provider.py,sha256=9RXRAocYEVWS6NR2PsOg7wtqiF8989x1BxAqgBSoLOI,16438
48
+ src/infrastructure/scm/gitlab_provider.py,sha256=mznhtBhXtc4zRut_Jb0pM57RIXViNYYiKiM7VKDFhl8,13881
49
+ src/review/__init__.py,sha256=XVyQZFf6UAqIKi8Gb1pQ4dKjcrC50soUvNuKu1DBspc,687
50
+ src/review/diff_normalizer.py,sha256=PRXQ7b81EBH1nx_8_Tm9G7Kjdax_6hIVtFgEixicT0E,3551
51
+ src/review/diff_source.py,sha256=O8bIlff0Zr7wPMzCKAVk_LF2pMDr3sc9KAuyA3OvHG0,2664
52
+ src/review/remote_pr.py,sha256=maPCQO5p7u9-_PA0FEBNgimfA6na2BdQGBPmqNj1_0c,11817
53
+ src/review/render.py,sha256=Hnkz0PvtYIaaikTS1inTzrneAJL4Xqjd-F8Lr6Yh6mQ,2691
54
+ src/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ src/ui/chat_app.py,sha256=6qpjWxHECYbKc5PTfbr63FjGo0j5-gXf3X-qW1klWBg,25396
56
+ src/ui/config_app.py,sha256=xgppZbEBFrFijgLGo1b1PN1vTGCg8xpI8gpMYBv2KzU,73417
57
+ src/ui/help_screen.py,sha256=EvbP8kFZ6Sdehi7bJ6Wo_YcTTk5MTkgneeidWwefYrA,1890
58
+ src/ui/issue_app.py,sha256=eINMmamloeopbtwyS1rCPwosaHeZW5oLebnEV4TfamY,9281
59
+ src/ui/linter_app.py,sha256=Y5vwU7D5PQIR_HaY6t40jZy7Guc8z2w-auyosCQqoro,1566
60
+ src/ui/metrics_app.py,sha256=a3jsB_kjMusSL57A6LpJyb9LFN7JJWlOdUNClklwq-c,16016
61
+ src/ui/pr_publish_app.py,sha256=cZ9xr1TSZF6fjvQPlAdSjzSNykufHF1l7hsmo3Ib2j0,67311
62
+ src/ui/pr_publish_help.py,sha256=fBiUtD97ngxbSfAvPVGGXU19r5kbALCKyi4QeKqyQ2c,1891
63
+ gitpr_cli-1.2.0.dist-info/METADATA,sha256=1BSAiMJtMgY7j3YsU0YgaHw7rpfk2ccj5z2iOzSjyxk,34689
64
+ gitpr_cli-1.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
65
+ gitpr_cli-1.2.0.dist-info/entry_points.txt,sha256=TstGnMUzdOI5qNmpM97EPDBPuMqOZxoo6EoLxHSOMSQ,71
66
+ gitpr_cli-1.2.0.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
67
+ gitpr_cli-1.2.0.dist-info/RECORD,,
src/cache.py CHANGED
@@ -47,9 +47,22 @@ def get_cached_response(action_folder, prompt_text):
47
47
 
48
48
 
49
49
  def save_cached_response(
50
- action_folder, action_type, prompt_text, response_dict, meta_raw=None
50
+ action_folder,
51
+ action_type,
52
+ prompt_text,
53
+ response_dict,
54
+ meta_raw=None,
55
+ reviewed_diff=None,
51
56
  ):
52
- """Saves the AI response to the local cache."""
57
+ """Saves the AI response to the local cache.
58
+
59
+ ``reviewed_diff`` is the diff the review actually ran on. When given it is
60
+ stored at the top level of the record, so ``gitpr fix`` can re-derive its
61
+ patch from the revision that was reviewed instead of whatever the working
62
+ tree happens to hold later — the two differ whenever the review came from a
63
+ pull request (src/review/remote_pr.py) or from a full-branch diff. Records
64
+ written before this field existed simply lack it, and the reader falls back.
65
+ """
53
66
  md5_hash = generate_md5(prompt_text)
54
67
  folder_path = get_cache_base_dir() / action_folder
55
68
  folder_path.mkdir(parents=True, exist_ok=True)
@@ -76,6 +89,9 @@ def save_cached_response(
76
89
  "response": response_dict,
77
90
  }
78
91
 
92
+ if reviewed_diff is not None:
93
+ cache_data["diff"] = reviewed_diff
94
+
79
95
  try:
80
96
  with open(cache_file, "w", encoding="utf-8") as f:
81
97
  json.dump(cache_data, f, indent=2, ensure_ascii=False)
@@ -83,6 +99,51 @@ def save_cached_response(
83
99
  pass # Silent cache failure to avoid crashing the tool
84
100
 
85
101
 
102
+ # Review action types whose prompt is a branch diff. `filereview` is left out
103
+ # on purpose: it audits a single file and has no diff to re-derive.
104
+ REVIEW_ACTION_TYPES = ("review", "fullreview")
105
+
106
+
107
+ def resolve_last_review(repo_name, branch_name):
108
+ """The most recent cached review for *repo_name* and *branch_name*, or None.
109
+
110
+ All three review modes write into the same ``review/`` folder (see
111
+ ``core.generate_pr_content``), so ``action_type`` is what tells them apart —
112
+ without that filter a file audit would be mistaken for a branch review.
113
+
114
+ Returns the cache record itself: the caller reads
115
+ ``record["response"]["review"]`` for the text and ``record["action_type"]``
116
+ to know which diff produced it, so the patch can be re-derived against
117
+ today's tree rather than the tree of the day the review ran.
118
+ """
119
+ review_folder = get_cache_base_dir() / "review"
120
+ if not review_folder.exists():
121
+ return None
122
+
123
+ newest = None
124
+ for cache_file in review_folder.glob("*.json"):
125
+ try:
126
+ with open(cache_file, "r", encoding="utf-8", errors="replace") as f:
127
+ data = json.load(f)
128
+ except (json.JSONDecodeError, IOError):
129
+ continue
130
+
131
+ if not isinstance(data, dict):
132
+ continue
133
+ if data.get("repo") != repo_name or data.get("branch") != branch_name:
134
+ continue
135
+ if data.get("action_type") not in REVIEW_ACTION_TYPES:
136
+ continue
137
+ if not (data.get("response") or {}).get("review"):
138
+ continue
139
+
140
+ # Timestamps are '%Y-%m-%d %H:%M:%S', so string order is date order.
141
+ if newest is None or data.get("datetime", "") > newest.get("datetime", ""):
142
+ newest = data
143
+
144
+ return newest
145
+
146
+
86
147
  def get_cached_pr_descriptions(repo_name, branch_name):
87
148
  """Searches the cache for all historically generated PRs for this repository and branch."""
88
149
  from src.i18n import __