gac 1.9.4__py3-none-any.whl → 1.10.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.
Potentially problematic release.
This version of gac might be problematic. Click here for more details.
- gac/__version__.py +1 -1
- gac/ai.py +17 -7
- gac/ai_utils.py +4 -6
- gac/init_cli.py +1 -0
- gac/main.py +58 -81
- gac/providers/__init__.py +2 -0
- gac/providers/fireworks.py +38 -0
- gac-1.10.0.dist-info/METADATA +220 -0
- {gac-1.9.4.dist-info → gac-1.10.0.dist-info}/RECORD +12 -11
- gac-1.9.4.dist-info/METADATA +0 -246
- {gac-1.9.4.dist-info → gac-1.10.0.dist-info}/WHEEL +0 -0
- {gac-1.9.4.dist-info → gac-1.10.0.dist-info}/entry_points.txt +0 -0
- {gac-1.9.4.dist-info → gac-1.10.0.dist-info}/licenses/LICENSE +0 -0
gac/__version__.py
CHANGED
gac/ai.py
CHANGED
|
@@ -13,6 +13,7 @@ from gac.providers import (
|
|
|
13
13
|
call_anthropic_api,
|
|
14
14
|
call_cerebras_api,
|
|
15
15
|
call_chutes_api,
|
|
16
|
+
call_fireworks_api,
|
|
16
17
|
call_gemini_api,
|
|
17
18
|
call_groq_api,
|
|
18
19
|
call_lmstudio_api,
|
|
@@ -30,7 +31,7 @@ logger = logging.getLogger(__name__)
|
|
|
30
31
|
|
|
31
32
|
def generate_commit_message(
|
|
32
33
|
model: str,
|
|
33
|
-
prompt: str | tuple[str, str],
|
|
34
|
+
prompt: str | tuple[str, str] | list[dict[str, str]],
|
|
34
35
|
temperature: float = EnvDefaults.TEMPERATURE,
|
|
35
36
|
max_tokens: int = EnvDefaults.MAX_OUTPUT_TOKENS,
|
|
36
37
|
max_retries: int = EnvDefaults.MAX_RETRIES,
|
|
@@ -59,18 +60,28 @@ def generate_commit_message(
|
|
|
59
60
|
'docs: Update README with installation instructions'
|
|
60
61
|
"""
|
|
61
62
|
# Handle both old (string) and new (tuple) prompt formats
|
|
62
|
-
if isinstance(prompt,
|
|
63
|
+
if isinstance(prompt, list):
|
|
64
|
+
messages = [{**msg} for msg in prompt]
|
|
65
|
+
elif isinstance(prompt, tuple):
|
|
63
66
|
system_prompt, user_prompt = prompt
|
|
67
|
+
messages = [
|
|
68
|
+
{"role": "system", "content": system_prompt or ""},
|
|
69
|
+
{"role": "user", "content": user_prompt},
|
|
70
|
+
]
|
|
64
71
|
else:
|
|
65
|
-
# Backward compatibility: treat string as user prompt with
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
# Backward compatibility: treat string as user prompt with empty system prompt
|
|
73
|
+
user_prompt = str(prompt)
|
|
74
|
+
messages = [
|
|
75
|
+
{"role": "system", "content": ""},
|
|
76
|
+
{"role": "user", "content": user_prompt},
|
|
77
|
+
]
|
|
68
78
|
|
|
69
79
|
# Provider functions mapping
|
|
70
80
|
provider_funcs = {
|
|
71
81
|
"anthropic": call_anthropic_api,
|
|
72
82
|
"cerebras": call_cerebras_api,
|
|
73
83
|
"chutes": call_chutes_api,
|
|
84
|
+
"fireworks": call_fireworks_api,
|
|
74
85
|
"gemini": call_gemini_api,
|
|
75
86
|
"groq": call_groq_api,
|
|
76
87
|
"lm-studio": call_lmstudio_api,
|
|
@@ -88,8 +99,7 @@ def generate_commit_message(
|
|
|
88
99
|
return generate_with_retries(
|
|
89
100
|
provider_funcs=provider_funcs,
|
|
90
101
|
model=model,
|
|
91
|
-
|
|
92
|
-
user_prompt=user_prompt,
|
|
102
|
+
messages=messages,
|
|
93
103
|
temperature=temperature,
|
|
94
104
|
max_tokens=max_tokens,
|
|
95
105
|
max_retries=max_retries,
|
gac/ai_utils.py
CHANGED
|
@@ -78,8 +78,7 @@ def _classify_error(error_str: str) -> str:
|
|
|
78
78
|
def generate_with_retries(
|
|
79
79
|
provider_funcs: dict,
|
|
80
80
|
model: str,
|
|
81
|
-
|
|
82
|
-
user_prompt: str,
|
|
81
|
+
messages: list[dict[str, str]],
|
|
83
82
|
temperature: float,
|
|
84
83
|
max_tokens: int,
|
|
85
84
|
max_retries: int,
|
|
@@ -97,6 +96,7 @@ def generate_with_retries(
|
|
|
97
96
|
"anthropic",
|
|
98
97
|
"cerebras",
|
|
99
98
|
"chutes",
|
|
99
|
+
"fireworks",
|
|
100
100
|
"gemini",
|
|
101
101
|
"groq",
|
|
102
102
|
"lm-studio",
|
|
@@ -111,10 +111,8 @@ def generate_with_retries(
|
|
|
111
111
|
if provider not in supported_providers:
|
|
112
112
|
raise AIError.model_error(f"Unsupported provider: {provider}. Supported providers: {supported_providers}")
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{"role": "user", "content": user_prompt},
|
|
117
|
-
]
|
|
114
|
+
if not messages:
|
|
115
|
+
raise AIError.model_error("No messages provided for AI generation")
|
|
118
116
|
|
|
119
117
|
# Set up spinner
|
|
120
118
|
if quiet:
|
gac/init_cli.py
CHANGED
|
@@ -35,6 +35,7 @@ def init() -> None:
|
|
|
35
35
|
("Anthropic", "claude-haiku-4-5"),
|
|
36
36
|
("Cerebras", "qwen-3-coder-480b"),
|
|
37
37
|
("Chutes", "zai-org/GLM-4.6-FP8"),
|
|
38
|
+
("Fireworks", "accounts/fireworks/models/gpt-oss-20b"),
|
|
38
39
|
("Gemini", "gemini-2.5-flash"),
|
|
39
40
|
("Groq", "meta-llama/llama-4-maverick-17b-128e-instruct"),
|
|
40
41
|
("LM Studio", "gemma3"),
|
gac/main.py
CHANGED
|
@@ -202,39 +202,49 @@ def main(
|
|
|
202
202
|
)
|
|
203
203
|
)
|
|
204
204
|
|
|
205
|
+
conversation_messages: list[dict[str, str]] = []
|
|
206
|
+
if system_prompt:
|
|
207
|
+
conversation_messages.append({"role": "system", "content": system_prompt})
|
|
208
|
+
conversation_messages.append({"role": "user", "content": user_prompt})
|
|
209
|
+
|
|
205
210
|
try:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
211
|
+
first_iteration = True
|
|
212
|
+
|
|
213
|
+
while True:
|
|
214
|
+
prompt_tokens = count_tokens(conversation_messages, model)
|
|
215
|
+
|
|
216
|
+
if first_iteration:
|
|
217
|
+
warning_limit_val = config.get("warning_limit_tokens", EnvDefaults.WARNING_LIMIT_TOKENS)
|
|
218
|
+
assert warning_limit_val is not None
|
|
219
|
+
warning_limit = int(warning_limit_val)
|
|
220
|
+
if warning_limit and prompt_tokens > warning_limit:
|
|
221
|
+
console.print(
|
|
222
|
+
f"[yellow]⚠️ WARNING: Prompt contains {prompt_tokens} tokens, which exceeds the warning limit of "
|
|
223
|
+
f"{warning_limit} tokens.[/yellow]"
|
|
224
|
+
)
|
|
225
|
+
if require_confirmation:
|
|
226
|
+
proceed = click.confirm("Do you want to continue anyway?", default=True)
|
|
227
|
+
if not proceed:
|
|
228
|
+
console.print("[yellow]Aborted due to token limit.[/yellow]")
|
|
229
|
+
sys.exit(0)
|
|
230
|
+
|
|
231
|
+
first_iteration = False
|
|
232
|
+
|
|
233
|
+
raw_commit_message = generate_commit_message(
|
|
234
|
+
model=model,
|
|
235
|
+
prompt=conversation_messages,
|
|
236
|
+
temperature=temperature,
|
|
237
|
+
max_tokens=max_output_tokens,
|
|
238
|
+
max_retries=max_retries,
|
|
239
|
+
quiet=quiet,
|
|
216
240
|
)
|
|
217
|
-
|
|
218
|
-
proceed = click.confirm("Do you want to continue anyway?", default=True)
|
|
219
|
-
if not proceed:
|
|
220
|
-
console.print("[yellow]Aborted due to token limit.[/yellow]")
|
|
221
|
-
sys.exit(0)
|
|
241
|
+
commit_message = clean_commit_message(raw_commit_message)
|
|
222
242
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
prompt=(system_prompt, user_prompt),
|
|
226
|
-
temperature=temperature,
|
|
227
|
-
max_tokens=max_output_tokens,
|
|
228
|
-
max_retries=max_retries,
|
|
229
|
-
quiet=quiet,
|
|
230
|
-
)
|
|
231
|
-
commit_message = clean_commit_message(commit_message)
|
|
243
|
+
logger.info("Generated commit message:")
|
|
244
|
+
logger.info(commit_message)
|
|
232
245
|
|
|
233
|
-
|
|
234
|
-
logger.info(commit_message)
|
|
246
|
+
conversation_messages.append({"role": "assistant", "content": commit_message})
|
|
235
247
|
|
|
236
|
-
# Reroll loop
|
|
237
|
-
while True:
|
|
238
248
|
console.print("[bold green]Generated commit message:[/bold green]")
|
|
239
249
|
console.print(Panel(commit_message, title="Commit Message", border_style="cyan"))
|
|
240
250
|
|
|
@@ -252,71 +262,38 @@ def main(
|
|
|
252
262
|
response = click.prompt(
|
|
253
263
|
"Proceed with commit above? [y/n/r <feedback>]", type=str, show_default=False
|
|
254
264
|
).strip()
|
|
265
|
+
response_lower = response.lower()
|
|
255
266
|
|
|
256
|
-
if
|
|
257
|
-
break
|
|
258
|
-
|
|
267
|
+
if response_lower in ["y", "yes"]:
|
|
268
|
+
break
|
|
269
|
+
if response_lower in ["n", "no"]:
|
|
259
270
|
console.print("[yellow]Prompt not accepted. Exiting...[/yellow]")
|
|
260
271
|
sys.exit(0)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
if response_lower == "r" or response_lower == "reroll" or response_lower.startswith("r "):
|
|
273
|
+
if response_lower == "r" or response_lower == "reroll":
|
|
274
|
+
feedback_message = (
|
|
275
|
+
"Please provide an alternative commit message using the same repository context."
|
|
276
|
+
)
|
|
266
277
|
console.print("[cyan]Regenerating commit message...[/cyan]")
|
|
267
278
|
else:
|
|
268
|
-
|
|
269
|
-
|
|
279
|
+
reroll_feedback = response[2:].strip()
|
|
280
|
+
feedback_message = (
|
|
281
|
+
f"Please revise the commit message based on this feedback: {reroll_feedback}"
|
|
282
|
+
)
|
|
270
283
|
console.print(f"[cyan]Regenerating commit message with feedback: {reroll_feedback}[/cyan]")
|
|
271
284
|
|
|
272
|
-
|
|
273
|
-
combined_hint = hint
|
|
274
|
-
if reroll_feedback:
|
|
275
|
-
# Create conversational prompt with previous attempt and feedback
|
|
276
|
-
conversational_hint = f"Previous attempt: '{commit_message}'. User feedback: {reroll_feedback}. Please revise accordingly."
|
|
277
|
-
|
|
278
|
-
if hint:
|
|
279
|
-
combined_hint = f"{hint}. {conversational_hint}"
|
|
280
|
-
else:
|
|
281
|
-
combined_hint = conversational_hint
|
|
282
|
-
|
|
283
|
-
# Regenerate prompt with conversational feedback
|
|
284
|
-
reroll_system_prompt, reroll_user_prompt = build_prompt(
|
|
285
|
-
status=status,
|
|
286
|
-
processed_diff=processed_diff,
|
|
287
|
-
diff_stat=diff_stat,
|
|
288
|
-
one_liner=one_liner,
|
|
289
|
-
hint=combined_hint,
|
|
290
|
-
infer_scope=infer_scope,
|
|
291
|
-
verbose=verbose,
|
|
292
|
-
)
|
|
293
|
-
else:
|
|
294
|
-
# No hint given, just reroll with same prompts
|
|
295
|
-
reroll_system_prompt, reroll_user_prompt = system_prompt, user_prompt
|
|
285
|
+
conversation_messages.append({"role": "user", "content": feedback_message})
|
|
296
286
|
|
|
297
287
|
console.print() # Add blank line for readability
|
|
288
|
+
break
|
|
289
|
+
|
|
290
|
+
console.print(
|
|
291
|
+
"[red]Invalid response. Please enter y (yes), n (no), r (reroll), or r <feedback>.[/red]"
|
|
292
|
+
)
|
|
298
293
|
|
|
299
|
-
|
|
300
|
-
commit_message = generate_commit_message(
|
|
301
|
-
model=model,
|
|
302
|
-
prompt=(reroll_system_prompt, reroll_user_prompt),
|
|
303
|
-
temperature=temperature,
|
|
304
|
-
max_tokens=max_output_tokens,
|
|
305
|
-
max_retries=max_retries,
|
|
306
|
-
quiet=quiet,
|
|
307
|
-
)
|
|
308
|
-
commit_message = clean_commit_message(commit_message)
|
|
309
|
-
break # Exit inner loop, continue outer loop
|
|
310
|
-
else:
|
|
311
|
-
console.print(
|
|
312
|
-
"[red]Invalid response. Please enter y (yes), n (no), r (reroll), or r <feedback>.[/red]"
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
# If we got here with 'y', break the outer loop
|
|
316
|
-
if response.lower() in ["y", "yes"]:
|
|
294
|
+
if response_lower in ["y", "yes"]:
|
|
317
295
|
break
|
|
318
296
|
else:
|
|
319
|
-
# No confirmation required, exit loop
|
|
320
297
|
break
|
|
321
298
|
|
|
322
299
|
if dry_run:
|
gac/providers/__init__.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from .anthropic import call_anthropic_api
|
|
4
4
|
from .cerebras import call_cerebras_api
|
|
5
5
|
from .chutes import call_chutes_api
|
|
6
|
+
from .fireworks import call_fireworks_api
|
|
6
7
|
from .gemini import call_gemini_api
|
|
7
8
|
from .groq import call_groq_api
|
|
8
9
|
from .lmstudio import call_lmstudio_api
|
|
@@ -17,6 +18,7 @@ __all__ = [
|
|
|
17
18
|
"call_anthropic_api",
|
|
18
19
|
"call_cerebras_api",
|
|
19
20
|
"call_chutes_api",
|
|
21
|
+
"call_fireworks_api",
|
|
20
22
|
"call_gemini_api",
|
|
21
23
|
"call_groq_api",
|
|
22
24
|
"call_lmstudio_api",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Fireworks AI API provider for gac."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from gac.errors import AIError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def call_fireworks_api(model: str, messages: list[dict], temperature: float, max_tokens: int) -> str:
|
|
11
|
+
"""Call Fireworks AI API directly."""
|
|
12
|
+
api_key = os.getenv("FIREWORKS_API_KEY")
|
|
13
|
+
if not api_key:
|
|
14
|
+
raise AIError.authentication_error("FIREWORKS_API_KEY not found in environment variables")
|
|
15
|
+
|
|
16
|
+
url = "https://api.fireworks.ai/inference/v1/chat/completions"
|
|
17
|
+
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
|
18
|
+
|
|
19
|
+
data = {"model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens}
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
response = httpx.post(url, headers=headers, json=data, timeout=120)
|
|
23
|
+
response.raise_for_status()
|
|
24
|
+
response_data = response.json()
|
|
25
|
+
content = response_data["choices"][0]["message"]["content"]
|
|
26
|
+
if content is None:
|
|
27
|
+
raise AIError.model_error("Fireworks AI API returned null content")
|
|
28
|
+
if content == "":
|
|
29
|
+
raise AIError.model_error("Fireworks AI API returned empty content")
|
|
30
|
+
return content
|
|
31
|
+
except httpx.HTTPStatusError as e:
|
|
32
|
+
if e.response.status_code == 429:
|
|
33
|
+
raise AIError.rate_limit_error(f"Fireworks AI API rate limit exceeded: {e.response.text}") from e
|
|
34
|
+
raise AIError.model_error(f"Fireworks AI API error: {e.response.status_code} - {e.response.text}") from e
|
|
35
|
+
except httpx.TimeoutException as e:
|
|
36
|
+
raise AIError.timeout_error(f"Fireworks AI API request timed out: {str(e)}") from e
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise AIError.model_error(f"Error calling Fireworks AI API: {str(e)}") from e
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gac
|
|
3
|
+
Version: 1.10.0
|
|
4
|
+
Summary: LLM-powered Git commit message generator with multi-provider support
|
|
5
|
+
Project-URL: Homepage, https://github.com/cellwebb/gac
|
|
6
|
+
Project-URL: Documentation, https://github.com/cellwebb/gac#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/cellwebb/gac.git
|
|
8
|
+
Project-URL: Issues, https://github.com/cellwebb/gac/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/cellwebb/gac/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Source, https://github.com/cellwebb/gac
|
|
11
|
+
Author-email: cellwebb <cellwebb@users.noreply.github.com>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: click>=8.3.0
|
|
25
|
+
Requires-Dist: halo
|
|
26
|
+
Requires-Dist: httpcore>=1.0.9
|
|
27
|
+
Requires-Dist: httpx>=0.28.0
|
|
28
|
+
Requires-Dist: pydantic>=2.12.0
|
|
29
|
+
Requires-Dist: python-dotenv>=1.1.1
|
|
30
|
+
Requires-Dist: questionary
|
|
31
|
+
Requires-Dist: rich>=14.1.0
|
|
32
|
+
Requires-Dist: tiktoken>=0.12.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build; extra == 'dev'
|
|
35
|
+
Requires-Dist: codecov; extra == 'dev'
|
|
36
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
40
|
+
Requires-Dist: twine; extra == 'dev'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
<!-- markdownlint-disable MD013 -->
|
|
44
|
+
|
|
45
|
+
# 🚀 Git Auto Commit (gac)
|
|
46
|
+
|
|
47
|
+
[](https://pypi.org/project/gac/)
|
|
48
|
+
[](https://www.python.org/downloads/)
|
|
49
|
+
[](https://github.com/cellwebb/gac/actions)
|
|
50
|
+
[](https://app.codecov.io/gh/cellwebb/gac)
|
|
51
|
+
[](https://github.com/astral-sh/ruff)
|
|
52
|
+
[](https://mypy-lang.org/)
|
|
53
|
+
[](docs/CONTRIBUTING.md)
|
|
54
|
+
[](LICENSE)
|
|
55
|
+
|
|
56
|
+
**LLM-powered commit messages that understand your code.**
|
|
57
|
+
|
|
58
|
+
**Tired of writing commit messages?** Replace `git commit -m "..."` with `gac` for contextual, well-formatted commit messages generated by large language models.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## What You Get
|
|
63
|
+
|
|
64
|
+
Instead of generic messages like `"update stuff"`, `"fix bug"`, or `"add feature"`, you get intelligent, contextual messages that explain the **why** behind your changes:
|
|
65
|
+
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### Use without installing
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uvx gac init # Configure your LLM provider
|
|
76
|
+
uvx gac # Generate and commit with LLM
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
That's it! Review the generated message and confirm with `y`.
|
|
80
|
+
|
|
81
|
+
### Install gac globally
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
uv tool install gac
|
|
85
|
+
gac init
|
|
86
|
+
gac
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Key Features
|
|
92
|
+
|
|
93
|
+
### 🌐 **Supported Providers**
|
|
94
|
+
|
|
95
|
+
- **Anthropic** • **Cerebras** • **Chutes.ai** • **Fireworks** • **Gemini**
|
|
96
|
+
- **Groq** • **LM Studio** • **Ollama** • **OpenAI** • **OpenRouter**
|
|
97
|
+
- **Streamlake** • **Synthetic.new** • **Z.AI** • **Z.AI Coding**
|
|
98
|
+
|
|
99
|
+
### 🧠 **Smart LLM Analysis**
|
|
100
|
+
|
|
101
|
+
- **Understands intent**: Analyzes code structure, logic, and patterns to understand the "why" behind your changes, not just what changed
|
|
102
|
+
- **Semantic awareness**: Recognizes refactoring, bug fixes, features, and breaking changes to generate contextually appropriate messages
|
|
103
|
+
- **Intelligent filtering**: Prioritizes meaningful changes while ignoring generated files, dependencies, and artifacts
|
|
104
|
+
|
|
105
|
+
### 📝 **Multiple Message Formats**
|
|
106
|
+
|
|
107
|
+
- **One-liner** (-o flag): Single-line commit message following conventional commit format
|
|
108
|
+
- **Standard** (default): Summary with bullet points explaining implementation details
|
|
109
|
+
- **Verbose** (-v flag): Comprehensive explanations including motivation, technical approach, and impact analysis
|
|
110
|
+
|
|
111
|
+
### 💻 **Developer Experience**
|
|
112
|
+
|
|
113
|
+
- **Interactive feedback**: Regenerate messages with specific requests like `r "make it shorter"` or `r "focus on the bug fix"`
|
|
114
|
+
- **One-command workflows**: Complete workflows with flags like `gac -ayp` (stage all, auto-confirm, push)
|
|
115
|
+
- **Git integration**: Respects pre-commit and lefthook hooks, running them before expensive LLM operations
|
|
116
|
+
|
|
117
|
+
### 🛡️ **Built-in Security**
|
|
118
|
+
|
|
119
|
+
- **Automatic secret detection**: Scans for API keys, passwords, and tokens before committing
|
|
120
|
+
- **Interactive protection**: Prompts before committing potentially sensitive data with clear remediation options
|
|
121
|
+
- **Smart filtering**: Ignores example files, template files, and placeholder text to reduce false positives
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Usage Examples
|
|
126
|
+
|
|
127
|
+
### Basic Workflow
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Stage your changes
|
|
131
|
+
git add .
|
|
132
|
+
|
|
133
|
+
# Generate and commit with LLM
|
|
134
|
+
gac
|
|
135
|
+
|
|
136
|
+
# Review → y (commit) | n (cancel) | r (reroll)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Common Commands
|
|
140
|
+
|
|
141
|
+
| Command | Description |
|
|
142
|
+
| --------------- | ---------------------------------------------- |
|
|
143
|
+
| `gac` | Generate commit message |
|
|
144
|
+
| `gac -y` | Auto-confirm (no review needed) |
|
|
145
|
+
| `gac -a` | Stage all + commit |
|
|
146
|
+
| `gac -o` | One-line message only |
|
|
147
|
+
| `gac -v` | Detailed verbose format |
|
|
148
|
+
| `gac -h "hint"` | Add context for LLM (e.g., `gac -h "bug fix"`) |
|
|
149
|
+
| `gac -s` | Include scope (e.g., feat(auth):) |
|
|
150
|
+
| `gac -p` | Commit and push |
|
|
151
|
+
|
|
152
|
+
### Power User Examples
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Complete workflow in one command
|
|
156
|
+
gac -ayp -h "release preparation"
|
|
157
|
+
|
|
158
|
+
# Detailed explanation with scope
|
|
159
|
+
gac -v -s
|
|
160
|
+
|
|
161
|
+
# Quick one-liner for small changes
|
|
162
|
+
gac -o
|
|
163
|
+
|
|
164
|
+
# Debug what the LLM sees
|
|
165
|
+
gac --show-prompt
|
|
166
|
+
|
|
167
|
+
# Skip security scan (use carefully)
|
|
168
|
+
gac --skip-secret-scan
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Interactive Reroll System
|
|
172
|
+
|
|
173
|
+
Not happy with the result? Use the reroll feature for intelligent regeneration:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Simple regeneration (uses previous context)
|
|
177
|
+
r
|
|
178
|
+
|
|
179
|
+
# With specific feedback
|
|
180
|
+
r make it shorter and focus on the performance improvement
|
|
181
|
+
r use conventional commit format with scope
|
|
182
|
+
r explain the security implications
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Configuration
|
|
188
|
+
|
|
189
|
+
Run `gac init` to configure your provider interactively, or set environment variables:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Example configuration
|
|
193
|
+
GAC_MODEL=anthropic:your-model-name
|
|
194
|
+
OPENAI_API_KEY=your_key_here
|
|
195
|
+
ANTHROPIC_API_KEY=your_key_here
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
See `.gac.env.example` for all available options.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Getting Help
|
|
203
|
+
|
|
204
|
+
- **Full documentation**: [USAGE.md](USAGE.md) - Complete CLI reference
|
|
205
|
+
- **Troubleshooting**: [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) - Common issues and solutions
|
|
206
|
+
- **Contributing**: [CONTRIBUTING.md](docs/CONTRIBUTING.md) - Development setup and guidelines
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
<!-- markdownlint-disable MD033 MD036 -->
|
|
211
|
+
|
|
212
|
+
<div align="center">
|
|
213
|
+
|
|
214
|
+
Made with ❤️ for developers who want better commit messages
|
|
215
|
+
|
|
216
|
+
[⭐ Star us on GitHub](https://github.com/cellwebb/gac) • [🐛 Report issues](https://github.com/cellwebb/gac/issues) • [📖 Full docs](USAGE.md)
|
|
217
|
+
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<!-- markdownlint-enable MD033 MD036 -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
|
|
2
|
-
gac/__version__.py,sha256=
|
|
3
|
-
gac/ai.py,sha256
|
|
4
|
-
gac/ai_utils.py,sha256=
|
|
2
|
+
gac/__version__.py,sha256=aS2cFuCUqXoCZQnjW0wEIKh2TEv5x4FSMZ7E_W-xkiA,67
|
|
3
|
+
gac/ai.py,sha256=QSGPrtFuzZh4LIjIt2HKVtdZ07xtSQXJRT7fxJ-Fufs,3898
|
|
4
|
+
gac/ai_utils.py,sha256=NBxmYAPLj3YcFHuo3TCJ4kpCtpAxnGJ7aG6_1Af9VOw,7314
|
|
5
5
|
gac/cli.py,sha256=crUUI6osYtE3QAZ7r6DRlVk9gR3X2PctzS1sssVQ9_g,5070
|
|
6
6
|
gac/config.py,sha256=n3TkQYBqSKkH68QUM6M7kwSK83ghmItoh0p5ZDFnhHA,1746
|
|
7
7
|
gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
|
|
@@ -9,16 +9,17 @@ gac/constants.py,sha256=8GHB7yeK2CYT0t80-k9N6LvgZPe-StNH3dK3NsUO46c,4977
|
|
|
9
9
|
gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
|
|
10
10
|
gac/errors.py,sha256=ysDIVRCd0YQVTOW3Q6YzdolxCdtkoQCAFf3_jrqbjUY,7916
|
|
11
11
|
gac/git.py,sha256=g6tvph50zV-wrTWrxARYXEpl0NeI8-ffFwHoqhp3fSE,8033
|
|
12
|
-
gac/init_cli.py,sha256=
|
|
13
|
-
gac/main.py,sha256=
|
|
12
|
+
gac/init_cli.py,sha256=YZAFRWcQ1TeXCGwEEyBeCwai2QYa1U0ErBCE8shkSkU,4804
|
|
13
|
+
gac/main.py,sha256=dJrBSN5rJlbWspLGDx3eUJU4uZFVhvuv7qtgIvF7RH4,14723
|
|
14
14
|
gac/preprocess.py,sha256=aMxsjGxy9YP752NWjgf0KP5Sn6p8keIJAGlMYr8jDgQ,15373
|
|
15
15
|
gac/prompt.py,sha256=d_kBXmhf3bDVLyDj8J7AS7GBAxF2jlc8lXoHX3Dzi5k,24255
|
|
16
16
|
gac/security.py,sha256=15Yp6YR8QC4eECJi1BUCkMteh_veZXUbLL6W8qGcDm4,9920
|
|
17
17
|
gac/utils.py,sha256=nV42-brIHW_fBg7x855GM8nRrqEBbRzTSweg-GTyGE8,3971
|
|
18
|
-
gac/providers/__init__.py,sha256=
|
|
18
|
+
gac/providers/__init__.py,sha256=26G8YJgZh2gK21bNjuDmPOTPeU8kbJz6HmUcvm0TOfw,944
|
|
19
19
|
gac/providers/anthropic.py,sha256=VK5d1s1PmBNDwh_x7illQ2CIZIHNIYU28btVfizwQPs,2036
|
|
20
20
|
gac/providers/cerebras.py,sha256=Ik8lhlsliGJVkgDgqlThfpra9tqbdYQZkaC4eNxRd9w,1648
|
|
21
21
|
gac/providers/chutes.py,sha256=cclJOLuGVIiiaF-9Bs1kH6SSOhEmduGB2zZ86KIaXKw,2617
|
|
22
|
+
gac/providers/fireworks.py,sha256=zsWhf6LMVdtsD9keXRFwgn9lCQigz6VmrDl6vqIVkdI,1688
|
|
22
23
|
gac/providers/gemini.py,sha256=GZQz6Y9fd5-xk-U4pXn9bXLeBowxDXOYDyWyrtjFurM,2909
|
|
23
24
|
gac/providers/groq.py,sha256=9v2fAjDa_iRNHFptiUBN8Vt7ZDKkW_JOmIBeYvycD1M,2806
|
|
24
25
|
gac/providers/lmstudio.py,sha256=R82-f0tWdFfGQxLT6o3Q2tfvYguF7ESUg9DEUHNyrDk,2146
|
|
@@ -28,8 +29,8 @@ gac/providers/openrouter.py,sha256=H3ce8JcRUYq1I30lOjGESdX7jfoPkW3mKAYnc2aYfBw,2
|
|
|
28
29
|
gac/providers/streamlake.py,sha256=KAA2ZnpuEI5imzvdWVWUhEBHSP0BMnprKXte6CbwBWY,2047
|
|
29
30
|
gac/providers/synthetic.py,sha256=sRMIJTS9LpcXd9A7qp_ZjZxdqtTKRn9fl1W4YwJZP4c,1855
|
|
30
31
|
gac/providers/zai.py,sha256=kywhhrCfPBu0rElZyb-iENxQxxpVGykvePuL4xrXlaU,2739
|
|
31
|
-
gac-1.
|
|
32
|
-
gac-1.
|
|
33
|
-
gac-1.
|
|
34
|
-
gac-1.
|
|
35
|
-
gac-1.
|
|
32
|
+
gac-1.10.0.dist-info/METADATA,sha256=AxOVZrY2wmdN1Oez8aYF959Rf49NFQYKHpGe16X_pvU,7698
|
|
33
|
+
gac-1.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
34
|
+
gac-1.10.0.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
|
|
35
|
+
gac-1.10.0.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
|
|
36
|
+
gac-1.10.0.dist-info/RECORD,,
|
gac-1.9.4.dist-info/METADATA
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: gac
|
|
3
|
-
Version: 1.9.4
|
|
4
|
-
Summary: AI-powered Git commit message generator with multi-provider support
|
|
5
|
-
Project-URL: Homepage, https://github.com/cellwebb/gac
|
|
6
|
-
Project-URL: Documentation, https://github.com/cellwebb/gac#readme
|
|
7
|
-
Project-URL: Repository, https://github.com/cellwebb/gac.git
|
|
8
|
-
Project-URL: Issues, https://github.com/cellwebb/gac/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/cellwebb/gac/blob/main/CHANGELOG.md
|
|
10
|
-
Project-URL: Source, https://github.com/cellwebb/gac
|
|
11
|
-
Author-email: cellwebb <cellwebb@users.noreply.github.com>
|
|
12
|
-
License-Expression: MIT
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Classifier: Development Status :: 4 - Beta
|
|
15
|
-
Classifier: Programming Language :: Python
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
-
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
|
-
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: anthropic>=0.68.0
|
|
25
|
-
Requires-Dist: click>=8.3.0
|
|
26
|
-
Requires-Dist: halo
|
|
27
|
-
Requires-Dist: httpcore>=1.0.9
|
|
28
|
-
Requires-Dist: httpx>=0.28.0
|
|
29
|
-
Requires-Dist: pydantic>=2.12.0
|
|
30
|
-
Requires-Dist: python-dotenv>=1.1.1
|
|
31
|
-
Requires-Dist: questionary
|
|
32
|
-
Requires-Dist: rich>=14.1.0
|
|
33
|
-
Requires-Dist: sumy
|
|
34
|
-
Requires-Dist: tiktoken>=0.12.0
|
|
35
|
-
Provides-Extra: dev
|
|
36
|
-
Requires-Dist: build; extra == 'dev'
|
|
37
|
-
Requires-Dist: codecov; extra == 'dev'
|
|
38
|
-
Requires-Dist: pre-commit; extra == 'dev'
|
|
39
|
-
Requires-Dist: pytest; extra == 'dev'
|
|
40
|
-
Requires-Dist: pytest-cov; extra == 'dev'
|
|
41
|
-
Requires-Dist: ruff; extra == 'dev'
|
|
42
|
-
Requires-Dist: twine; extra == 'dev'
|
|
43
|
-
Description-Content-Type: text/markdown
|
|
44
|
-
|
|
45
|
-
<!-- markdownlint-disable MD013 -->
|
|
46
|
-
|
|
47
|
-
# Git Auto Commit (gac)
|
|
48
|
-
|
|
49
|
-
[](https://pypi.org/project/gac/)
|
|
50
|
-
[](https://www.python.org/downloads/)
|
|
51
|
-
[](https://github.com/cellwebb/gac/actions)
|
|
52
|
-
[](https://app.codecov.io/gh/cellwebb/gac)
|
|
53
|
-
[](https://github.com/astral-sh/ruff)
|
|
54
|
-
[](https://mypy-lang.org/)
|
|
55
|
-
[](docs/CONTRIBUTING.md)
|
|
56
|
-
[](LICENSE)
|
|
57
|
-
|
|
58
|
-
## Features
|
|
59
|
-
|
|
60
|
-
- **LLM-Powered Commit Messages:** Automatically generates clear, concise, and context-aware commit messages using large language models.
|
|
61
|
-
- **Deep Contextual Analysis:** Understands your code by analyzing staged changes, repository structure, and recent commit history to provide highly relevant suggestions.
|
|
62
|
-
- **Multi-Provider & Model Support:** Flexibly works with leading AI providers (Anthropic, Cerebras, Chutes.ai, Gemini, Groq, OpenAI, OpenRouter, Streamlake/Vanchin, Synthetic.new, & Z.AI) and local providers (LM Studio & Ollama), easily configured through an interactive setup or environment variables.
|
|
63
|
-
- **Seamless Git Workflow:** Integrates smoothly into your existing Git routine as a simple drop-in replacement for `git commit`.
|
|
64
|
-
- **Extensive Customization:** Tailor commit messages to your needs with a rich set of flags, including one-liners (`-o`), detailed verbose messages (`-v`), AI hints (`-h`), scope inference (`-s`), and specific model selection (`-m`).
|
|
65
|
-
- **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.
|
|
66
|
-
- **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`).
|
|
67
|
-
- **Token Usage Tracking:** Display token consumption statistics (prompt, completion, and total tokens).
|
|
68
|
-
- **Security Scanner:** Built-in detection of secrets and API keys in staged changes to prevent accidental commits of sensitive information.
|
|
69
|
-
|
|
70
|
-
## How It Works
|
|
71
|
-
|
|
72
|
-
gac analyzes your staged changes to generate high-quality commit messages with the help of large language models. The tool uses a sophisticated prompt architecture that separates system instructions from user data, enabling better AI understanding and more consistent results.
|
|
73
|
-
|
|
74
|
-
## How to Use
|
|
75
|
-
|
|
76
|
-
```sh
|
|
77
|
-
git add .
|
|
78
|
-
gac
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-

|
|
82
|
-
|
|
83
|
-
## Installation and Configuration
|
|
84
|
-
|
|
85
|
-
### 1. Installation
|
|
86
|
-
|
|
87
|
-
#### Quick Try with uvx (no installation)
|
|
88
|
-
|
|
89
|
-
You can try gac without installing it using uvx:
|
|
90
|
-
|
|
91
|
-
```sh
|
|
92
|
-
# Try gac without installation
|
|
93
|
-
uvx gac --help
|
|
94
|
-
|
|
95
|
-
# Set up configuration (creates ~/.gac.env)
|
|
96
|
-
uvx gac init
|
|
97
|
-
|
|
98
|
-
# Use gac on staged changes
|
|
99
|
-
git add .
|
|
100
|
-
uvx gac
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
#### Permanent Installation
|
|
104
|
-
|
|
105
|
-
Install system-wide using pipx from the GitHub repository:
|
|
106
|
-
|
|
107
|
-
```sh
|
|
108
|
-
# Install pipx if you don't have it
|
|
109
|
-
python3 -m pip install --user pipx
|
|
110
|
-
python3 -m pipx ensurepath
|
|
111
|
-
|
|
112
|
-
# Install gac
|
|
113
|
-
pipx install gac
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Verify installation:
|
|
117
|
-
|
|
118
|
-
```sh
|
|
119
|
-
gac --version
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### 2. Configuration
|
|
123
|
-
|
|
124
|
-
The recommended way to configure `gac` is using the interactive setup:
|
|
125
|
-
|
|
126
|
-
```sh
|
|
127
|
-
gac init
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
This command will guide you through selecting an AI provider, model, and securely entering your API keys. It will create or update a user-level configuration file at `$HOME/.gac.env`.
|
|
131
|
-
|
|
132
|
-
Example `$HOME/.gac.env` output:
|
|
133
|
-
|
|
134
|
-
```env
|
|
135
|
-
GAC_MODEL=anthropic:claude-3-5-haiku-latest
|
|
136
|
-
ANTHROPIC_API_KEY=your_anthropic_key_here
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Alternatively, you can configure `gac` using environment variables or by manually creating/editing the configuration file.
|
|
140
|
-
|
|
141
|
-
#### Managing Configuration with `gac config`
|
|
142
|
-
|
|
143
|
-
You can manage settings in your `$HOME/.gac.env` file using `gac config` commands:
|
|
144
|
-
|
|
145
|
-
- Streamlake uses inference endpoint IDs instead of model names. When prompted, paste the exact endpoint ID from the Streamlake console.
|
|
146
|
-
- For local providers like Ollama and LM Studio, gac will ask for the base API URL. API keys are optional for these providers unless your instance requires authentication.
|
|
147
|
-
|
|
148
|
-
- Show config: `gac config show`
|
|
149
|
-
- Set a value: `gac config set GAC_MODEL groq:meta-llama/llama-4-scout-17b-16e-instruct`
|
|
150
|
-
- Get a value: `gac config get GAC_MODEL`
|
|
151
|
-
- Unset a value: `gac config unset GAC_MODEL`
|
|
152
|
-
|
|
153
|
-
### 3. Verify Setup
|
|
154
|
-
|
|
155
|
-
Test that `gac` is working properly with your configuration:
|
|
156
|
-
|
|
157
|
-
```sh
|
|
158
|
-
# Make a change to a file
|
|
159
|
-
echo "# Test change" >> README.md
|
|
160
|
-
git add README.md
|
|
161
|
-
gac -o # Generate a one-line commit message
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
You should see an AI-generated commit message.
|
|
165
|
-
|
|
166
|
-
### 4. Upgrade
|
|
167
|
-
|
|
168
|
-
To upgrade `gac` to the latest version, run:
|
|
169
|
-
|
|
170
|
-
```sh
|
|
171
|
-
pipx upgrade gac
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Basic Usage
|
|
175
|
-
|
|
176
|
-
Once installed and configured, using `gac` is straightforward:
|
|
177
|
-
|
|
178
|
-
1. Stage your changes:
|
|
179
|
-
|
|
180
|
-
```sh
|
|
181
|
-
git add .
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
2. Run `gac`:
|
|
185
|
-
|
|
186
|
-
```sh
|
|
187
|
-
gac
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
This will generate a commit message for review. Confirm with `y` to accept the message.
|
|
191
|
-
|
|
192
|
-
### Common Commands
|
|
193
|
-
|
|
194
|
-
- Generate a commit message: `gac`
|
|
195
|
-
- Auto-accept the commit message: `gac -y`
|
|
196
|
-
- Stage all changes and generate a commit message: `gac -a`
|
|
197
|
-
- Generate a one-line commit message: `gac -o`
|
|
198
|
-
- Add a hint for the AI: `gac -h "Fixed the authentication bug"`
|
|
199
|
-
- Push the commit (requires accepting the commit message): `gac -p`
|
|
200
|
-
- Advanced usage: Add all, auto-confirm, push a one-liner with a hint: `gac -aypo -h "update for release"`
|
|
201
|
-
- Skip security scan: `gac --skip-secret-scan` (use with caution)
|
|
202
|
-
|
|
203
|
-
### Security Features
|
|
204
|
-
|
|
205
|
-
GAC includes a built-in security scanner to prevent accidental commits of sensitive information:
|
|
206
|
-
|
|
207
|
-
- **Automatic Scanning**: By default, scans all staged changes for potential secrets and API keys
|
|
208
|
-
- **Interactive Protection**: When secrets are detected, you can:
|
|
209
|
-
- Abort the commit (recommended)
|
|
210
|
-
- Continue anyway (not recommended)
|
|
211
|
-
- Remove affected files and continue
|
|
212
|
-
- **Wide Coverage**: Detects AWS keys, GitHub tokens, OpenAI API keys, database URLs, private keys, and more
|
|
213
|
-
- **Smart Filtering**: Ignores example keys, placeholders, and test values to reduce false positives
|
|
214
|
-
|
|
215
|
-
To disable the security scan (not recommended unless you know what you're doing):
|
|
216
|
-
|
|
217
|
-
```sh
|
|
218
|
-
# Skip scan for one command
|
|
219
|
-
gac --skip-secret-scan
|
|
220
|
-
|
|
221
|
-
# Or disable via environment variable
|
|
222
|
-
export GAC_SKIP_SECRET_SCAN=true
|
|
223
|
-
gac
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
For a full list of CLI flags, advanced options, and example workflows, see [USAGE.md](USAGE.md).
|
|
227
|
-
|
|
228
|
-
## Best Practices
|
|
229
|
-
|
|
230
|
-
- gac loads configuration from two locations (in order of precedence):
|
|
231
|
-
1. User-level `$HOME/.gac.env` (applies to all projects for the user)
|
|
232
|
-
2. Project-level `.env` (in the project root, overrides user config if present) Environment variables always take final precedence over both files.
|
|
233
|
-
- Keep API keys out of version control
|
|
234
|
-
- For troubleshooting, see [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)
|
|
235
|
-
|
|
236
|
-
## Contributing
|
|
237
|
-
|
|
238
|
-
We welcome contributions! Please see [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines.
|
|
239
|
-
|
|
240
|
-
## License
|
|
241
|
-
|
|
242
|
-
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
243
|
-
|
|
244
|
-
## Community & Support
|
|
245
|
-
|
|
246
|
-
For questions, suggestions, or support, please open an issue or discussion on GitHub.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|