diffsage 1.2.0__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {diffsage-1.2.0/src/diffsage.egg-info → diffsage-1.3.0}/PKG-INFO +156 -29
  2. {diffsage-1.2.0 → diffsage-1.3.0}/README.md +155 -28
  3. {diffsage-1.2.0 → diffsage-1.3.0}/pyproject.toml +1 -1
  4. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/cli.py +7 -1
  5. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/ask.py +6 -0
  6. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/commit.py +23 -6
  7. diffsage-1.3.0/src/diffsage/commands/pr.py +220 -0
  8. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/__init__.py +31 -10
  9. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/base.py +12 -0
  10. diffsage-1.3.0/src/diffsage/exceptions/git.py +21 -0
  11. diffsage-1.3.0/src/diffsage/exceptions/github.py +13 -0
  12. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/git/client.py +102 -0
  13. diffsage-1.3.0/src/diffsage/github/client.py +65 -0
  14. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/commit_message.py +2 -0
  15. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/git.py +13 -1
  16. diffsage-1.3.0/src/diffsage/models/pull_request.py +27 -0
  17. diffsage-1.3.0/src/diffsage/models/pull_request_analysis.py +29 -0
  18. diffsage-1.3.0/src/diffsage/parsers/pull_request_parser.py +68 -0
  19. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/ai_service.py +11 -1
  20. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/commit_service.py +10 -2
  21. diffsage-1.3.0/src/diffsage/services/git_service.py +116 -0
  22. diffsage-1.3.0/src/diffsage/services/github_service.py +75 -0
  23. diffsage-1.3.0/src/diffsage/services/prompt_service.py +182 -0
  24. diffsage-1.3.0/src/diffsage/services/pull_request_analysis_service.py +281 -0
  25. diffsage-1.3.0/src/diffsage/services/pull_request_service.py +42 -0
  26. diffsage-1.3.0/src/diffsage/ui/__init__.py +0 -0
  27. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/commit_view.py +2 -2
  28. diffsage-1.3.0/src/diffsage/ui/pull_request_view.py +122 -0
  29. {diffsage-1.2.0 → diffsage-1.3.0/src/diffsage.egg-info}/PKG-INFO +156 -29
  30. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/SOURCES.txt +12 -1
  31. diffsage-1.2.0/src/diffsage/exceptions/git.py +0 -9
  32. diffsage-1.2.0/src/diffsage/services/git_service.py +0 -20
  33. diffsage-1.2.0/src/diffsage/services/prompt_service.py +0 -60
  34. {diffsage-1.2.0 → diffsage-1.3.0}/LICENSE +0 -0
  35. {diffsage-1.2.0 → diffsage-1.3.0}/setup.cfg +0 -0
  36. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/__init__.py +0 -0
  37. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/__main__.py +0 -0
  38. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/__init__.py +0 -0
  39. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/auth.py +0 -0
  40. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/config.py +0 -0
  41. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/doctor.py +0 -0
  42. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/__init__.py +0 -0
  43. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/defaults.py +0 -0
  44. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/file_loader.py +0 -0
  45. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/loader.py +0 -0
  46. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/paths.py +0 -0
  47. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/resolver.py +0 -0
  48. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/schema.py +0 -0
  49. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/scope.py +0 -0
  50. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/settings.py +0 -0
  51. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/credentials.py +0 -0
  52. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/provider.py +0 -0
  53. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/git/__init__.py +0 -0
  54. {diffsage-1.2.0/src/diffsage/logging → diffsage-1.3.0/src/diffsage/github}/__init__.py +0 -0
  55. {diffsage-1.2.0/src/diffsage/models → diffsage-1.3.0/src/diffsage/logging}/__init__.py +0 -0
  56. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/logging/formatter.py +0 -0
  57. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/logging/logger.py +0 -0
  58. {diffsage-1.2.0/src/diffsage/prompts → diffsage-1.3.0/src/diffsage/models}/__init__.py +0 -0
  59. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/config.py +0 -0
  60. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/credentials.py +0 -0
  61. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/doctor.py +0 -0
  62. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/provider.py +0 -0
  63. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/parsers/commit_message_parser.py +0 -0
  64. {diffsage-1.2.0/src/diffsage/providers → diffsage-1.3.0/src/diffsage/prompts}/__init__.py +0 -0
  65. {diffsage-1.2.0/src/diffsage/services → diffsage-1.3.0/src/diffsage/providers}/__init__.py +0 -0
  66. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/base.py +0 -0
  67. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/factory.py +0 -0
  68. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/gemini_provider.py +0 -0
  69. {diffsage-1.2.0/src/diffsage/storage → diffsage-1.3.0/src/diffsage/services}/__init__.py +0 -0
  70. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/config_service.py +0 -0
  71. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/credentials_service.py +0 -0
  72. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/doctor_service.py +0 -0
  73. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/editor_service.py +0 -0
  74. {diffsage-1.2.0/src/diffsage/ui → diffsage-1.3.0/src/diffsage/storage}/__init__.py +0 -0
  75. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/base.py +0 -0
  76. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/config_repository.py +0 -0
  77. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/credentials_repository.py +0 -0
  78. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/ask_view.py +0 -0
  79. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/auth_view.py +0 -0
  80. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/base.py +0 -0
  81. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/config_view.py +0 -0
  82. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/doctor_view.py +0 -0
  83. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/dependency_links.txt +0 -0
  84. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/entry_points.txt +0 -0
  85. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/requires.txt +0 -0
  86. {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffsage
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: AI-powered Git workflow assistant
5
5
  Author: Gunitha Rathnayake
6
6
  License: MIT
@@ -116,6 +116,10 @@ Current capabilities include:
116
116
  - AI provider authentication and error handling
117
117
  - Layered architecture
118
118
  - Comprehensive automated test suite
119
+ - Add AI-assisted PR generation
120
+ - Interactive PR draft review/edit/regeneration
121
+ - GitHub PR creation
122
+ - Branch synchronization validation
119
123
 
120
124
  ---
121
125
 
@@ -150,18 +154,38 @@ Its scope is intentionally focused on improving Git workflows.
150
154
 
151
155
  # Project Status
152
156
 
153
- > **Current Stage:** Active Development
157
+ > **Current Stage:** Alpha
154
158
 
155
- DiffSage is currently under active development.
159
+ DiffSage is an actively developed open-source project.
156
160
 
157
- The project is being developed privately while the core architecture, documentation, and workflow foundation are finalized.
161
+ The project is published on PyPI and distributed as a Python package for
162
+ developers, automation, and AI agents.
158
163
 
159
- The long-term goal is to open source the project once it reaches a stable and well-documented foundation.
164
+ The current focus is on expanding Git workflow capabilities while maintaining
165
+ a stable architecture, clear documentation, reliable automation, and strong
166
+ engineering practices.
160
167
 
161
168
  ---
162
169
 
163
170
  # Installation
164
171
 
172
+ ## User Installation
173
+
174
+ DiffSage is published on PyPI and can be installed using `pipx`.
175
+
176
+ DiffSage currently requires Python 3.12.
177
+
178
+ ```bash
179
+ pipx install diffsage
180
+ ```
181
+
182
+ After installation verify the environment
183
+ ```bash
184
+ diffsage doctor
185
+ ```
186
+
187
+ ## Developer Installation
188
+
165
189
  Clone the repository:
166
190
 
167
191
  ```bash
@@ -192,9 +216,29 @@ Windows
192
216
  Install the project:
193
217
 
194
218
  ```bash
195
- pip install -e ".[dev]"
219
+ python -m pip install -e ".[dev]"
220
+ ```
221
+
222
+ ---
223
+
224
+ # Releases
225
+
226
+ DiffSage releases are published through GitHub Releases and distributed through PyPI.
227
+
228
+ Released package versions can be installed directly with:
229
+
230
+ ```bash
231
+ pipx install diffsage
232
+ ```
233
+
234
+ A specific version can be installed with:
235
+
236
+ ```bash
237
+ pipx install diffsage==1.2.0
196
238
  ```
197
239
 
240
+ Release builds and PyPI publishing are automated through GitHub Actions.
241
+
198
242
  ---
199
243
 
200
244
  # Configuration
@@ -203,17 +247,18 @@ DiffSage supports layered configuration through global and repository-local TOML
203
247
 
204
248
  Application configuration controls how DiffSage behaves and can be managed through global, repository-local, and environment-based configuration.
205
249
 
206
- Provider credentials are managed separately from application configuration.
207
250
  Provider credentials are managed separately from application configuration and are not part of the Settings configuration model.
208
251
 
209
252
  ```env
210
253
  DIFFSAGE_PROVIDER=gemini
211
- DIFFSAGE_AI_MODEL=gemini-3.5-flash-lite
254
+ DIFFSAGE_AI_MODEL=<provider-supported-model>
212
255
  DIFFSAGE_LOG_LEVEL=INFO
213
256
  DIFFSAGE_TIMEOUT=60
214
257
  DIFFSAGE_MAX_RETRIES=3
215
258
  ```
216
259
 
260
+ The configured model must be supported by the selected AI provider.
261
+
217
262
  Configuration can also be managed directly from the CLI:
218
263
 
219
264
  ```bash
@@ -272,10 +317,38 @@ Display AI suggestion
272
317
  [N] Cancel
273
318
  ```
274
319
 
320
+ ```bash
321
+ diffsage pr
322
+ ```
323
+
324
+ PR workflow
325
+
326
+ ```text
327
+ Generate PR draft
328
+ │
329
+ ▼
330
+ Show base/head branches
331
+ │
332
+ ▼
333
+ Display PR draft
334
+ │
335
+ ┌─────┼───────────┐
336
+ ▼ ▼ ▼
337
+ Edit Regenerate Cancel
338
+ │
339
+ ▼
340
+ Accept
341
+ │
342
+ ▼
343
+ Create GitHub PR
344
+ │
345
+ ▼
346
+ Display PR URL
347
+ ```
348
+
275
349
  Named credential profiles are also supported:
276
350
 
277
351
  ```bash
278
-
279
352
  diffsage auth set gemini YOUR_API_KEY --name paid
280
353
  ```
281
354
 
@@ -300,6 +373,8 @@ diffsage auth unset gemini
300
373
  |----------|-------------|
301
374
  | `diffsage doctor` | Validate the local DiffSage environment |
302
375
  | `diffsage commit` | Generate and manage AI-assisted commit messages |
376
+ | `diffsage pr` | Generate, review, and create a GitHub pull request |
377
+ | `diffsage pr <base-branch>` | Generate and create a pull request against a specific base branch |
303
378
  | `diffsage config list` | Display the current DiffSage configuration |
304
379
  | `diffsage config get` | Display the value of a configuration setting |
305
380
  | `diffsage config set` | Update a configuration setting |
@@ -310,7 +385,46 @@ diffsage auth unset gemini
310
385
  | `diffsage auth unset` | Remove a provider credential |
311
386
  | `diffsage ask` | Ask the configured AI provider a question |
312
387
 
313
- More commands will be introduced as the project evolves.
388
+ ---
389
+
390
+ ## Pull Request Workflow
391
+
392
+ The `diffsage pr` command analyzes the current Git branch against a resolved base branch and generates a structured pull request draft.
393
+
394
+ The workflow is interactive:
395
+
396
+ ```text
397
+ Analyze Git repository
398
+ │
399
+ ▼
400
+ Resolve base branch
401
+ │
402
+ ▼
403
+ Generate PR draft
404
+ │
405
+ ▼
406
+ Display base/head branches
407
+ │
408
+ ▼
409
+ Review PR draft
410
+ │
411
+ ┌──────┼──────────────┐
412
+ ▼ ▼ ▼
413
+ Edit Regenerate Cancel
414
+ │ │
415
+ └──────┴───────┐
416
+ ▼
417
+ Accept
418
+ │
419
+ ▼
420
+ Validate GitHub access
421
+ │
422
+ ▼
423
+ Create GitHub pull request
424
+ │
425
+ ▼
426
+ Display pull request URL
427
+ ```
314
428
 
315
429
  ---
316
430
 
@@ -328,15 +442,22 @@ Commands
328
442
  │
329
443
  ├── Authentication
330
444
  │
331
- ▼
332
- Services
333
- │
334
- ├── Git
335
- ├── AI
336
- ├── Prompt Generation
337
- └── Credentials
445
+ ├── Commit Workflow
338
446
  │
339
- ▼
447
+ └── Pull Request Workflow
448
+ │
449
+ ▼
450
+ Services
451
+ │
452
+ ├── Git
453
+ ├── GitHub
454
+ ├── AI
455
+ ├── Prompt Generation
456
+ ├── Pull Request Analysis
457
+ ├── Pull Request Parsing
458
+ └── Credentials
459
+ │
460
+ ▼
340
461
  Providers / Storage
341
462
  ```
342
463
 
@@ -362,6 +483,7 @@ src/
362
483
  ├── config/
363
484
  ├── exceptions/
364
485
  ├── git/
486
+ ├── github/
365
487
  ├── logging/
366
488
  ├── models/
367
489
  ├── parsers/
@@ -372,6 +494,18 @@ src/
372
494
  └── ui/
373
495
 
374
496
  tests/
497
+ ├── commands/
498
+ ├── config/
499
+ ├── git/
500
+ ├── github/
501
+ ├── integration/
502
+ ├── models/
503
+ ├── parsers/
504
+ ├── prompts/
505
+ ├── providers/
506
+ ├── services/
507
+ ├── storage/
508
+ └── ui/
375
509
 
376
510
  docs/
377
511
  ```
@@ -390,10 +524,6 @@ Additional project documentation is available within the repository.
390
524
  | `docs/changelog.md` | Project changes and milestones |
391
525
  | `docs/adrs/ADR-*` | Architecture Decision Records (ADRs) |
392
526
 
393
- Future documentation will include:
394
-
395
- - Contributing Guide
396
-
397
527
  ---
398
528
 
399
529
  # Roadmap
@@ -424,6 +554,7 @@ Instead of requiring every automation tool or AI agent to implement Git workflow
424
554
 
425
555
  - Repository validation
426
556
  - Git operations
557
+ - GitHub integration
427
558
  - AI integration
428
559
  - Workflow execution
429
560
  - Error handling
@@ -452,15 +583,11 @@ Features that fall outside these principles intentionally remain out of scope.
452
583
 
453
584
  # Contributing
454
585
 
455
- Contribution guidelines will be published when the project becomes publicly available.
456
-
457
- Future contributors will be encouraged to review:
586
+ DiffSage is an open-source project and contributions are welcome.
458
587
 
459
- - Architecture documentation
460
- - Coding conventions
461
- - ADRs
588
+ Before contributing, review the project architecture, coding conventions, and architectural decision records in the `docs/` directory.
462
589
 
463
- before submitting changes.
590
+ Additional contribution guidelines will be documented as the project evolves.
464
591
 
465
592
  ---
466
593
 
@@ -77,6 +77,10 @@ Current capabilities include:
77
77
  - AI provider authentication and error handling
78
78
  - Layered architecture
79
79
  - Comprehensive automated test suite
80
+ - Add AI-assisted PR generation
81
+ - Interactive PR draft review/edit/regeneration
82
+ - GitHub PR creation
83
+ - Branch synchronization validation
80
84
 
81
85
  ---
82
86
 
@@ -111,18 +115,38 @@ Its scope is intentionally focused on improving Git workflows.
111
115
 
112
116
  # Project Status
113
117
 
114
- > **Current Stage:** Active Development
118
+ > **Current Stage:** Alpha
115
119
 
116
- DiffSage is currently under active development.
120
+ DiffSage is an actively developed open-source project.
117
121
 
118
- The project is being developed privately while the core architecture, documentation, and workflow foundation are finalized.
122
+ The project is published on PyPI and distributed as a Python package for
123
+ developers, automation, and AI agents.
119
124
 
120
- The long-term goal is to open source the project once it reaches a stable and well-documented foundation.
125
+ The current focus is on expanding Git workflow capabilities while maintaining
126
+ a stable architecture, clear documentation, reliable automation, and strong
127
+ engineering practices.
121
128
 
122
129
  ---
123
130
 
124
131
  # Installation
125
132
 
133
+ ## User Installation
134
+
135
+ DiffSage is published on PyPI and can be installed using `pipx`.
136
+
137
+ DiffSage currently requires Python 3.12.
138
+
139
+ ```bash
140
+ pipx install diffsage
141
+ ```
142
+
143
+ After installation verify the environment
144
+ ```bash
145
+ diffsage doctor
146
+ ```
147
+
148
+ ## Developer Installation
149
+
126
150
  Clone the repository:
127
151
 
128
152
  ```bash
@@ -153,9 +177,29 @@ Windows
153
177
  Install the project:
154
178
 
155
179
  ```bash
156
- pip install -e ".[dev]"
180
+ python -m pip install -e ".[dev]"
181
+ ```
182
+
183
+ ---
184
+
185
+ # Releases
186
+
187
+ DiffSage releases are published through GitHub Releases and distributed through PyPI.
188
+
189
+ Released package versions can be installed directly with:
190
+
191
+ ```bash
192
+ pipx install diffsage
193
+ ```
194
+
195
+ A specific version can be installed with:
196
+
197
+ ```bash
198
+ pipx install diffsage==1.2.0
157
199
  ```
158
200
 
201
+ Release builds and PyPI publishing are automated through GitHub Actions.
202
+
159
203
  ---
160
204
 
161
205
  # Configuration
@@ -164,17 +208,18 @@ DiffSage supports layered configuration through global and repository-local TOML
164
208
 
165
209
  Application configuration controls how DiffSage behaves and can be managed through global, repository-local, and environment-based configuration.
166
210
 
167
- Provider credentials are managed separately from application configuration.
168
211
  Provider credentials are managed separately from application configuration and are not part of the Settings configuration model.
169
212
 
170
213
  ```env
171
214
  DIFFSAGE_PROVIDER=gemini
172
- DIFFSAGE_AI_MODEL=gemini-3.5-flash-lite
215
+ DIFFSAGE_AI_MODEL=<provider-supported-model>
173
216
  DIFFSAGE_LOG_LEVEL=INFO
174
217
  DIFFSAGE_TIMEOUT=60
175
218
  DIFFSAGE_MAX_RETRIES=3
176
219
  ```
177
220
 
221
+ The configured model must be supported by the selected AI provider.
222
+
178
223
  Configuration can also be managed directly from the CLI:
179
224
 
180
225
  ```bash
@@ -233,10 +278,38 @@ Display AI suggestion
233
278
  [N] Cancel
234
279
  ```
235
280
 
281
+ ```bash
282
+ diffsage pr
283
+ ```
284
+
285
+ PR workflow
286
+
287
+ ```text
288
+ Generate PR draft
289
+ │
290
+ ▼
291
+ Show base/head branches
292
+ │
293
+ ▼
294
+ Display PR draft
295
+ │
296
+ ┌─────┼───────────┐
297
+ ▼ ▼ ▼
298
+ Edit Regenerate Cancel
299
+ │
300
+ ▼
301
+ Accept
302
+ │
303
+ ▼
304
+ Create GitHub PR
305
+ │
306
+ ▼
307
+ Display PR URL
308
+ ```
309
+
236
310
  Named credential profiles are also supported:
237
311
 
238
312
  ```bash
239
-
240
313
  diffsage auth set gemini YOUR_API_KEY --name paid
241
314
  ```
242
315
 
@@ -261,6 +334,8 @@ diffsage auth unset gemini
261
334
  |----------|-------------|
262
335
  | `diffsage doctor` | Validate the local DiffSage environment |
263
336
  | `diffsage commit` | Generate and manage AI-assisted commit messages |
337
+ | `diffsage pr` | Generate, review, and create a GitHub pull request |
338
+ | `diffsage pr <base-branch>` | Generate and create a pull request against a specific base branch |
264
339
  | `diffsage config list` | Display the current DiffSage configuration |
265
340
  | `diffsage config get` | Display the value of a configuration setting |
266
341
  | `diffsage config set` | Update a configuration setting |
@@ -271,7 +346,46 @@ diffsage auth unset gemini
271
346
  | `diffsage auth unset` | Remove a provider credential |
272
347
  | `diffsage ask` | Ask the configured AI provider a question |
273
348
 
274
- More commands will be introduced as the project evolves.
349
+ ---
350
+
351
+ ## Pull Request Workflow
352
+
353
+ The `diffsage pr` command analyzes the current Git branch against a resolved base branch and generates a structured pull request draft.
354
+
355
+ The workflow is interactive:
356
+
357
+ ```text
358
+ Analyze Git repository
359
+ │
360
+ ▼
361
+ Resolve base branch
362
+ │
363
+ ▼
364
+ Generate PR draft
365
+ │
366
+ ▼
367
+ Display base/head branches
368
+ │
369
+ ▼
370
+ Review PR draft
371
+ │
372
+ ┌──────┼──────────────┐
373
+ ▼ ▼ ▼
374
+ Edit Regenerate Cancel
375
+ │ │
376
+ └──────┴───────┐
377
+ ▼
378
+ Accept
379
+ │
380
+ ▼
381
+ Validate GitHub access
382
+ │
383
+ ▼
384
+ Create GitHub pull request
385
+ │
386
+ ▼
387
+ Display pull request URL
388
+ ```
275
389
 
276
390
  ---
277
391
 
@@ -289,15 +403,22 @@ Commands
289
403
  │
290
404
  ├── Authentication
291
405
  │
292
- ▼
293
- Services
294
- │
295
- ├── Git
296
- ├── AI
297
- ├── Prompt Generation
298
- └── Credentials
406
+ ├── Commit Workflow
299
407
  │
300
- ▼
408
+ └── Pull Request Workflow
409
+ │
410
+ ▼
411
+ Services
412
+ │
413
+ ├── Git
414
+ ├── GitHub
415
+ ├── AI
416
+ ├── Prompt Generation
417
+ ├── Pull Request Analysis
418
+ ├── Pull Request Parsing
419
+ └── Credentials
420
+ │
421
+ ▼
301
422
  Providers / Storage
302
423
  ```
303
424
 
@@ -323,6 +444,7 @@ src/
323
444
  ├── config/
324
445
  ├── exceptions/
325
446
  ├── git/
447
+ ├── github/
326
448
  ├── logging/
327
449
  ├── models/
328
450
  ├── parsers/
@@ -333,6 +455,18 @@ src/
333
455
  └── ui/
334
456
 
335
457
  tests/
458
+ ├── commands/
459
+ ├── config/
460
+ ├── git/
461
+ ├── github/
462
+ ├── integration/
463
+ ├── models/
464
+ ├── parsers/
465
+ ├── prompts/
466
+ ├── providers/
467
+ ├── services/
468
+ ├── storage/
469
+ └── ui/
336
470
 
337
471
  docs/
338
472
  ```
@@ -351,10 +485,6 @@ Additional project documentation is available within the repository.
351
485
  | `docs/changelog.md` | Project changes and milestones |
352
486
  | `docs/adrs/ADR-*` | Architecture Decision Records (ADRs) |
353
487
 
354
- Future documentation will include:
355
-
356
- - Contributing Guide
357
-
358
488
  ---
359
489
 
360
490
  # Roadmap
@@ -385,6 +515,7 @@ Instead of requiring every automation tool or AI agent to implement Git workflow
385
515
 
386
516
  - Repository validation
387
517
  - Git operations
518
+ - GitHub integration
388
519
  - AI integration
389
520
  - Workflow execution
390
521
  - Error handling
@@ -413,15 +544,11 @@ Features that fall outside these principles intentionally remain out of scope.
413
544
 
414
545
  # Contributing
415
546
 
416
- Contribution guidelines will be published when the project becomes publicly available.
417
-
418
- Future contributors will be encouraged to review:
547
+ DiffSage is an open-source project and contributions are welcome.
419
548
 
420
- - Architecture documentation
421
- - Coding conventions
422
- - ADRs
549
+ Before contributing, review the project architecture, coding conventions, and architectural decision records in the `docs/` directory.
423
550
 
424
- before submitting changes.
551
+ Additional contribution guidelines will be documented as the project evolves.
425
552
 
426
553
  ---
427
554
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "diffsage"
7
- version = "1.2.0"
7
+ version = "1.3.0"
8
8
  description = "AI-powered Git workflow assistant"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12,<3.13"
@@ -7,6 +7,7 @@ from diffsage.commands.auth import app as auth_app
7
7
  from diffsage.commands.commit import commit
8
8
  from diffsage.commands.config import app as config_app
9
9
  from diffsage.commands.doctor import doctor
10
+ from diffsage.commands.pr import pr
10
11
  from diffsage.config.loader import load_settings
11
12
  from diffsage.logging.logger import configure_logging
12
13
 
@@ -31,8 +32,13 @@ def main() -> None:
31
32
  app.command()(doctor)
32
33
  app.command()(ask)
33
34
  app.command()(commit)
35
+ app.command()(pr)
36
+
34
37
  app.add_typer(
35
38
  config_app,
36
39
  name="config",
37
40
  )
38
- app.add_typer(auth_app, name="auth")
41
+ app.add_typer(
42
+ auth_app,
43
+ name="auth",
44
+ )
@@ -4,6 +4,7 @@ from diffsage.exceptions import (
4
4
  AuthenticationError,
5
5
  ConfigError,
6
6
  CredentialNotFoundError,
7
+ ModelNotFoundError,
7
8
  ProviderUnavailableError,
8
9
  )
9
10
  from diffsage.logging.logger import get_logger
@@ -46,6 +47,11 @@ def ask(prompt: str) -> None:
46
47
  view.show_error(str(e))
47
48
  raise SystemExit(1) from None
48
49
 
50
+ except ModelNotFoundError as e:
51
+ logger.warning(str(e))
52
+ view.show_error(str(e))
53
+ raise SystemExit(1) from None
54
+
49
55
  except ProviderUnavailableError as e:
50
56
  logger.warning(str(e))
51
57
  view.show_error(str(e))
@@ -1,3 +1,5 @@
1
+ from collections.abc import Callable
2
+
1
3
  from diffsage.config.loader import load_settings
2
4
  from diffsage.config.paths import get_credentials_path
3
5
  from diffsage.exceptions import (
@@ -22,8 +24,13 @@ from diffsage.ui.commit_view import CommitView
22
24
  logger = get_logger(__name__)
23
25
 
24
26
 
25
- def generate_message(commit_service: CommitService) -> str:
26
- return commit_service.generate_commit_message()
27
+ def generate_message(
28
+ commit_service: CommitService,
29
+ on_attempt: Callable[[int, int], None] | None = None,
30
+ ) -> str:
31
+ return commit_service.generate_commit_message(
32
+ on_attempt=on_attempt,
33
+ )
27
34
 
28
35
 
29
36
  def commit() -> None:
@@ -54,8 +61,13 @@ def commit() -> None:
54
61
  ai_service,
55
62
  )
56
63
 
57
- with view.generating():
58
- raw_message = generate_message(commit_service)
64
+ with view.generating() as status:
65
+ raw_message = generate_message(
66
+ commit_service,
67
+ on_attempt=lambda attempt, total: status.update(
68
+ f"Generating commit message... Attempt {attempt}/{total}"
69
+ ),
70
+ )
59
71
  commit_message = CommitMessageParser.parse(raw_message)
60
72
 
61
73
  view.show_generated()
@@ -79,8 +91,13 @@ def commit() -> None:
79
91
 
80
92
  if choice == "r":
81
93
  logger.info("User selected regenerate.")
82
- with view.generating():
83
- raw_message = generate_message(commit_service)
94
+ with view.generating() as status:
95
+ raw_message = generate_message(
96
+ commit_service,
97
+ on_attempt=lambda attempt, total: status.update(
98
+ f"Generating commit message... Attempt {attempt}/{total}"
99
+ ),
100
+ )
84
101
  commit_message = CommitMessageParser.parse(raw_message)
85
102
 
86
103
  view.show_generated()