gac 0.16.3__py3-none-any.whl → 0.17.2__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.
gac/__version__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for gac package."""
2
2
 
3
- __version__ = "0.16.3"
3
+ __version__ = "0.17.2"
gac/cli.py CHANGED
@@ -87,6 +87,12 @@ def cli(
87
87
  effective_log_level = "ERROR"
88
88
  setup_logging(effective_log_level)
89
89
  logger.info("Starting gac")
90
+
91
+ # Apply always_include_scope setting if no explicit scope provided
92
+ effective_scope = scope
93
+ if scope is None and config.get("always_include_scope", False):
94
+ effective_scope = "" # Empty string triggers scope inference
95
+
90
96
  try:
91
97
  main(
92
98
  stage_all=add_all,
@@ -94,7 +100,7 @@ def cli(
94
100
  hint=hint,
95
101
  one_liner=one_liner,
96
102
  show_prompt=show_prompt,
97
- scope=scope,
103
+ scope=effective_scope,
98
104
  require_confirmation=not yes,
99
105
  push=push,
100
106
  quiet=quiet,
gac/config.py CHANGED
@@ -33,6 +33,8 @@ def load_config() -> dict[str, str | int | float | bool]:
33
33
  "max_retries": int(os.getenv("GAC_RETRIES", EnvDefaults.MAX_RETRIES)),
34
34
  "log_level": os.getenv("GAC_LOG_LEVEL", Logging.DEFAULT_LEVEL),
35
35
  "warning_limit_tokens": int(os.getenv("GAC_WARNING_LIMIT_TOKENS", EnvDefaults.WARNING_LIMIT_TOKENS)),
36
+ "always_include_scope": os.getenv("GAC_ALWAYS_INCLUDE_SCOPE", str(EnvDefaults.ALWAYS_INCLUDE_SCOPE)).lower()
37
+ in ("true", "1", "yes", "on"),
36
38
  }
37
39
 
38
40
  return config
gac/constants.py CHANGED
@@ -23,6 +23,7 @@ class EnvDefaults:
23
23
  TEMPERATURE: float = 1
24
24
  MAX_OUTPUT_TOKENS: int = 512
25
25
  WARNING_LIMIT_TOKENS: int = 16384
26
+ ALWAYS_INCLUDE_SCOPE: bool = False
26
27
 
27
28
 
28
29
  class Logging:
gac/git.py CHANGED
@@ -161,11 +161,16 @@ def push_changes() -> bool:
161
161
  return False
162
162
 
163
163
  try:
164
- run_git_command(["push"])
164
+ # Use raise_on_error=True to properly catch push failures
165
+ run_subprocess(["git", "push"], raise_on_error=True, strip_output=True)
165
166
  return True
166
- except GitError as e:
167
- if "fatal: No configured push destination" in str(e):
167
+ except subprocess.CalledProcessError as e:
168
+ error_msg = e.stderr.strip() if e.stderr else str(e)
169
+ if "fatal: No configured push destination" in error_msg:
168
170
  logger.error("No configured push destination.")
169
171
  else:
170
- logger.error(f"Failed to push changes: {e}")
172
+ logger.error(f"Failed to push changes: {error_msg}")
173
+ return False
174
+ except Exception as e:
175
+ logger.error(f"Failed to push changes: {e}")
171
176
  return False
gac/main.py CHANGED
@@ -121,7 +121,7 @@ def main(
121
121
  if warning_limit and prompt_tokens > warning_limit:
122
122
  console = Console()
123
123
  console.print(
124
- f"[yellow]⚠️ Warning: Prompt contains {prompt_tokens} tokens, which exceeds the warning limit of "
124
+ f"[yellow]⚠️ WARNING: Prompt contains {prompt_tokens} tokens, which exceeds the warning limit of "
125
125
  f"{warning_limit} tokens.[/yellow]"
126
126
  )
127
127
  if require_confirmation:
@@ -159,23 +159,58 @@ def main(
159
159
  )
160
160
 
161
161
  if require_confirmation:
162
- # Custom prompt that accepts y/n/r
162
+ # Custom prompt that accepts y/n/r or "r <feedback (optional)>"
163
163
  while True:
164
- response = (
165
- click.prompt("Proceed with commit above? [y/n/r]", type=str, show_default=False).lower().strip()
166
- )
164
+ response = click.prompt(
165
+ "Proceed with commit above? [y/n/r <feedback>]", type=str, show_default=False
166
+ ).strip()
167
167
 
168
- if response in ["y", "yes"]:
168
+ if response.lower() in ["y", "yes"]:
169
169
  break # Exit both loops and proceed with commit
170
- elif response in ["n", "no"]:
170
+ elif response.lower() in ["n", "no"]:
171
171
  console.print("[yellow]Prompt not accepted. Exiting...[/yellow]")
172
172
  sys.exit(0)
173
- elif response in ["r", "reroll"]:
174
- console.print("[cyan]Regenerating commit message...[/cyan]\n")
173
+ elif response.lower() == "r" or response.lower().startswith("r ") or response.lower() == "reroll":
174
+ # Parse the reroll command for optional feedback
175
+ if response.lower() == "r" or response.lower() == "reroll":
176
+ # Simple reroll without feedback
177
+ reroll_feedback = ""
178
+ console.print("[cyan]Regenerating commit message...[/cyan]")
179
+ else:
180
+ # Extract feedback from "r <feedback>"
181
+ reroll_feedback = response[2:].strip() # Remove "r " prefix
182
+ console.print(f"[cyan]Regenerating commit message with feedback: {reroll_feedback}[/cyan]")
183
+
184
+ # Combine hints if reroll feedback provided
185
+ combined_hint = hint
186
+ if reroll_feedback:
187
+ # Create conversational prompt with previous attempt and feedback
188
+ conversational_hint = f"Previous attempt: '{commit_message}'. User feedback: {reroll_feedback}. Please revise accordingly."
189
+
190
+ if hint:
191
+ combined_hint = f"{hint}. {conversational_hint}"
192
+ else:
193
+ combined_hint = conversational_hint
194
+
195
+ # Regenerate prompt with conversational feedback
196
+ reroll_prompt = build_prompt(
197
+ status=status,
198
+ processed_diff=processed_diff,
199
+ diff_stat=diff_stat,
200
+ one_liner=one_liner,
201
+ hint=combined_hint,
202
+ scope=scope,
203
+ )
204
+ else:
205
+ # No hint given, just reroll with same prompt
206
+ reroll_prompt = prompt
207
+
208
+ console.print() # Add blank line for readability
209
+
175
210
  # Generate new message
176
211
  commit_message = generate_commit_message(
177
212
  model=model,
178
- prompt=prompt,
213
+ prompt=reroll_prompt,
179
214
  temperature=temperature,
180
215
  max_tokens=max_output_tokens,
181
216
  max_retries=max_retries,
@@ -184,10 +219,12 @@ def main(
184
219
  commit_message = clean_commit_message(commit_message)
185
220
  break # Exit inner loop, continue outer loop
186
221
  else:
187
- console.print("[red]Invalid response. Please enter y (yes), n (no), or r (reroll).[/red]")
222
+ console.print(
223
+ "[red]Invalid response. Please enter y (yes), n (no), r (reroll), or r <feedback>.[/red]"
224
+ )
188
225
 
189
226
  # If we got here with 'y', break the outer loop
190
- if response in ["y", "yes"]:
227
+ if response.lower() in ["y", "yes"]:
191
228
  break
192
229
  else:
193
230
  # No confirmation required, exit loop
@@ -233,15 +270,13 @@ def main(
233
270
  logger.info("Changes pushed successfully")
234
271
  console.print("[green]Changes pushed successfully[/green]")
235
272
  else:
236
- handle_error(
237
- GitError("Failed to push changes. Check your remote configuration."),
238
- exit_program=True,
273
+ console.print(
274
+ "[red]Failed to push changes. Check your remote configuration and network connection.[/red]"
239
275
  )
276
+ sys.exit(1)
240
277
  except Exception as e:
241
- handle_error(
242
- GitError(f"Error pushing changes: {e}"),
243
- exit_program=True,
244
- )
278
+ console.print(f"[red]Error pushing changes: {e}[/red]")
279
+ sys.exit(1)
245
280
 
246
281
  if not quiet:
247
282
  logger.info("Successfully committed changes with message:")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gac
3
- Version: 0.16.3
3
+ Version: 0.17.2
4
4
  Summary: AI-powered Git commit message generator with multi-provider support
5
5
  Project-URL: Homepage, https://github.com/cellwebb/gac
6
6
  Project-URL: Documentation, https://github.com/cellwebb/gac#readme
@@ -66,7 +66,7 @@ Description-Content-Type: text/markdown
66
66
  - **Seamless Git Workflow:** Integrates smoothly into your existing Git routine as a simple drop-in replacement for `git commit`.
67
67
  - **Extensive Customization:** Tailor commit messages to your needs with a rich set of flags, including one-liners (`-o`), AI hints (`-h`), commit scope (`-s`), and specific model selection (`-m`).
68
68
  - **Streamlined Workflow Commands:** Boost your productivity with convenient options to stage all changes (`-a`), auto-confirm commits (`-y`), and push to your remote repository (`-p`) in a single step.
69
- - **Reroll Capability:** Not satisfied with the generated commit message? Simply type `r` or `reroll` at the confirmation prompt to generate a new message.
69
+ - **Interactive Reroll with Feedback:** Not satisfied with the generated commit message? Use `r` for a simple regeneration, or `r <feedback>` to provide specific improvement suggestions (e.g., `r make it shorter`, `r focus on the bug fix`).
70
70
  - **Token Usage Tracking:** Display token consumption statistics (prompt, completion, and total tokens).
71
71
 
72
72
  ## How It Works
@@ -0,0 +1,20 @@
1
+ gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
2
+ gac/__version__.py,sha256=v99UPabTLMGan0nh-8ujsEAomKUPy1bclqTXLNIKfx8,67
3
+ gac/ai.py,sha256=kxZ0UMU_2i9Vb2fXKAUcuFCeZJAZ9G8OSjgTVF06h-Y,5452
4
+ gac/cli.py,sha256=KsagQerqcf2uqGS4HjV_U1AUBtY3DPmYLsTj08riZmE,4545
5
+ gac/config.py,sha256=wSgEDjtis7Vk1pv5VPvYmJyD9-tymDS6GiUHjnCMbIM,1486
6
+ gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
7
+ gac/constants.py,sha256=MAxdASGncfZY1TdKGdhJZ0wvTBEU3gTN6KEdw8n3Bd8,4844
8
+ gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
9
+ gac/errors.py,sha256=3vIRMQ2QF3sP9_rPfXAFuu5ZSjIVX4FxM-FAuiR8N-8,7416
10
+ gac/git.py,sha256=MS2m4fv8h4mau1djFG1aje9NXTmkGsjPO9w18LqNGX0,6031
11
+ gac/init_cli.py,sha256=aNllguofrcLn0ML9tzLVWFkPbwlAvCM9m7undHhMLEo,1825
12
+ gac/main.py,sha256=yO17nqu78K4pHj4u9-enVDB2qetR1YWgqK4WBa4pXoM,11597
13
+ gac/preprocess.py,sha256=4igtZ9OTHgTpqwlJmbcGaqzmdD0HHCZJwsZ9eG118Gk,15360
14
+ gac/prompt.py,sha256=i6XPWXCC_v1k2wVkv5FlL540RKG5uS-U6HJU9wC-cGw,18291
15
+ gac/utils.py,sha256=W3ladtmsH01MNLdckQYTzYrYbTGEdzCKI36he9C-y_E,3945
16
+ gac-0.17.2.dist-info/METADATA,sha256=Yx64UZRoaV05ERPcv9-6_UOp4OF3PiiCMg4AdLHlpis,7654
17
+ gac-0.17.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ gac-0.17.2.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
19
+ gac-0.17.2.dist-info/licenses/LICENSE,sha256=s11puNmYfzwoSwG96nhOJe268Y1QFckr8-Hmzo3_eJE,1087
20
+ gac-0.17.2.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
2
- gac/__version__.py,sha256=ZrOgRPcn114KgqOkRlJyqV-9NfDnOY4PEJ2z42L5dj8,67
3
- gac/ai.py,sha256=kxZ0UMU_2i9Vb2fXKAUcuFCeZJAZ9G8OSjgTVF06h-Y,5452
4
- gac/cli.py,sha256=UCGaKpGrm8B603V04yMYGkfv9S5-CksSy7zzeqwp13s,4280
5
- gac/config.py,sha256=7gyD4dDZhb_xL0gjOxfA3cqmz-5LwaMUT3MCTAPBjug,1330
6
- gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
7
- gac/constants.py,sha256=7ynwnS6wxT3o7KEed1MZuWrJ9jGf-Yp5aIxRH8P3uwg,4805
8
- gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
9
- gac/errors.py,sha256=3vIRMQ2QF3sP9_rPfXAFuu5ZSjIVX4FxM-FAuiR8N-8,7416
10
- gac/git.py,sha256=csjPf9YzxpYaZjIzIfa0yKTV64q22f718j_Zc9Q9maQ,5725
11
- gac/init_cli.py,sha256=aNllguofrcLn0ML9tzLVWFkPbwlAvCM9m7undHhMLEo,1825
12
- gac/main.py,sha256=_BX_B9Denex9MwceT1udBQjzoMLLD2czU8TlHvPRE80,9520
13
- gac/preprocess.py,sha256=4igtZ9OTHgTpqwlJmbcGaqzmdD0HHCZJwsZ9eG118Gk,15360
14
- gac/prompt.py,sha256=i6XPWXCC_v1k2wVkv5FlL540RKG5uS-U6HJU9wC-cGw,18291
15
- gac/utils.py,sha256=W3ladtmsH01MNLdckQYTzYrYbTGEdzCKI36he9C-y_E,3945
16
- gac-0.16.3.dist-info/METADATA,sha256=TvCN3km323w51BSIuHKLE-PJVAoJU4RcUXeqGBeg_JU,7569
17
- gac-0.16.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- gac-0.16.3.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
19
- gac-0.16.3.dist-info/licenses/LICENSE,sha256=s11puNmYfzwoSwG96nhOJe268Y1QFckr8-Hmzo3_eJE,1087
20
- gac-0.16.3.dist-info/RECORD,,
File without changes