gac 2.1.0__py3-none-any.whl → 2.3.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/prompt.py CHANGED
@@ -246,30 +246,30 @@ DEFAULT_USER_TEMPLATE = """<hint>
246
246
  Additional context provided by the user: <hint_text></hint_text>
247
247
  </hint>
248
248
 
249
- <git_status>
250
- <status></status>
251
- </git_status>
249
+ <git_diff>
250
+ <diff></diff>
251
+ </git_diff>
252
252
 
253
253
  <git_diff_stat>
254
254
  <diff_stat></diff_stat>
255
255
  </git_diff_stat>
256
256
 
257
- <git_diff>
258
- <diff></diff>
259
- </git_diff>
257
+ <git_status>
258
+ <status></status>
259
+ </git_status>
260
+
261
+ <language_instructions>
262
+ IMPORTANT: You MUST write the entire commit message in <language_name></language_name>.
263
+ All text in the commit message, including the summary line and body, must be in <language_name></language_name>.
264
+ <prefix_instruction></prefix_instruction>
265
+ </language_instructions>
260
266
 
261
- <instructions>
267
+ <format_instructions>
262
268
  IMMEDIATELY AFTER ANALYZING THE CHANGES, RESPOND WITH ONLY THE COMMIT MESSAGE.
263
269
  DO NOT include any preamble, reasoning, explanations or anything other than the commit message itself.
264
270
  DO NOT use markdown formatting, headers, or code blocks.
265
271
  The entire response will be passed directly to 'git commit -m'.
266
-
267
- <language>
268
- IMPORTANT: You MUST write the entire commit message in <language_name></language_name>.
269
- All text in the commit message, including the summary line and body, must be in <language_name></language_name>.
270
- <prefix_instruction></prefix_instruction>
271
- </language>
272
- </instructions>"""
272
+ </format_instructions>"""
273
273
 
274
274
 
275
275
  # ============================================================================
@@ -518,7 +518,7 @@ The ENTIRE commit message, including the prefix, must be in {language}."""
518
518
 
519
519
  user_template = user_template.replace("<prefix_instruction></prefix_instruction>", prefix_instruction)
520
520
  else:
521
- user_template = _remove_template_section(user_template, "language")
521
+ user_template = _remove_template_section(user_template, "language_instructions")
522
522
  logger.debug("Using default language (English)")
523
523
 
524
524
  user_template = re.sub(r"\n(?:[ \t]*\n){2,}", "\n\n", user_template)
@@ -526,6 +526,92 @@ The ENTIRE commit message, including the prefix, must be in {language}."""
526
526
  return system_template.strip(), user_template.strip()
527
527
 
528
528
 
529
+ def build_group_prompt(
530
+ status: str,
531
+ processed_diff: str,
532
+ diff_stat: str,
533
+ one_liner: bool,
534
+ hint: str,
535
+ infer_scope: bool,
536
+ verbose: bool,
537
+ system_template_path: str | None,
538
+ language: str | None,
539
+ translate_prefixes: bool,
540
+ ) -> tuple[str, str]:
541
+ """Build prompt for grouped commit generation (JSON output with multiple commits)."""
542
+ system_prompt, user_prompt = build_prompt(
543
+ status=status,
544
+ processed_diff=processed_diff,
545
+ diff_stat=diff_stat,
546
+ one_liner=one_liner,
547
+ hint=hint,
548
+ infer_scope=infer_scope,
549
+ verbose=verbose,
550
+ system_template_path=system_template_path,
551
+ language=language,
552
+ translate_prefixes=translate_prefixes,
553
+ )
554
+
555
+ user_prompt = _remove_template_section(user_prompt, "format_instructions")
556
+
557
+ grouping_instructions = """
558
+ <format_instructions>
559
+ Your task is to split the changed files into separate, logical commits. Think of this like sorting files into different folders where each file belongs in exactly one folder.
560
+
561
+ CRITICAL REQUIREMENT - Every File Used Exactly Once:
562
+ You must assign EVERY file from the diff to exactly ONE commit.
563
+ - NO file should be left out
564
+ - NO file should appear in multiple commits
565
+ - EVERY file must be used once and ONLY once
566
+
567
+ Think of it like dealing cards: Once you've dealt a card to a player, that card cannot be dealt to another player.
568
+
569
+ HOW TO SPLIT THE FILES:
570
+ 1. Review all changed files in the diff
571
+ 2. Group files by logical relationship (e.g., related features, bug fixes, documentation)
572
+ 3. Assign each file to exactly one commit based on what makes the most sense
573
+ 4. If a file could fit in multiple commits, pick the best fit and move on - do NOT duplicate it
574
+ 5. Continue until every single file has been assigned to a commit
575
+
576
+ ORDERING:
577
+ Order the commits in a logical sequence considering dependencies, natural progression, and overall workflow.
578
+
579
+ YOUR RESPONSE FORMAT:
580
+ Respond with valid JSON following this structure:
581
+ ```json
582
+ {
583
+ "commits": [
584
+ {
585
+ "files": ["src/auth/login.ts", "src/auth/logout.ts"],
586
+ "message": "<commit_message_conforming_to_prescribed_structure_and_format>"
587
+ },
588
+ {
589
+ "files": ["src/db/schema.sql", "src/db/migrations/001.sql"],
590
+ "message": "<commit_message_conforming_to_prescribed_structure_and_format>"
591
+ },
592
+ {
593
+ "files": ["tests/auth.test.ts", "tests/db.test.ts", "README.md"],
594
+ "message": "<commit_message_conforming_to_prescribed_structure_and_format>"
595
+ }
596
+ ]
597
+ }
598
+ ```
599
+
600
+ ☝️ Notice how EVERY file path in the example above appears exactly ONCE across all commits. "src/auth/login.ts" appears once. "tests/auth.test.ts" appears once. No file is repeated.
601
+
602
+ VALIDATION CHECKLIST - Before responding, verify:
603
+ □ Total files across all commits = Total files in the diff
604
+ □ Each file appears in exactly 1 commit (no duplicates, no omissions)
605
+ □ Every commit has at least one file
606
+ □ If you list all files from all commits and count them, you get the same count as unique files in the diff
607
+ </format_instructions>
608
+ """
609
+
610
+ user_prompt = user_prompt + grouping_instructions
611
+
612
+ return system_prompt, user_prompt
613
+
614
+
529
615
  # ============================================================================
530
616
  # Message Cleaning Helpers
531
617
  # ============================================================================
gac/security.py CHANGED
@@ -54,7 +54,7 @@ class SecretPatterns:
54
54
  PRIVATE_KEY = re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----")
55
55
 
56
56
  # Bearer Tokens (require actual token with specific characteristics)
57
- BEARER_TOKEN = re.compile(r"Bearer\s+[A-Za-z0-9]{20,}[/=]*\s", re.IGNORECASE)
57
+ BEARER_TOKEN = re.compile(r"Bearer\s+[A-Za-z0-9]{20,}[/=]*(?:\s|$)", re.IGNORECASE)
58
58
 
59
59
  # JWT Tokens
60
60
  JWT_TOKEN = re.compile(r"eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+")
gac/utils.py CHANGED
@@ -130,3 +130,141 @@ def run_subprocess(
130
130
  # Convert generic exceptions to CalledProcessError for consistency
131
131
  raise subprocess.CalledProcessError(1, command, "", str(e)) from e
132
132
  return ""
133
+
134
+
135
+ def edit_commit_message_inplace(message: str) -> str | None:
136
+ """Edit commit message in-place using rich terminal editing.
137
+
138
+ Uses prompt_toolkit to provide a rich editing experience with:
139
+ - Multi-line editing
140
+ - Vi/Emacs key bindings
141
+ - Line editing capabilities
142
+ - Esc+Enter or Ctrl+S to submit
143
+ - Ctrl+C to cancel
144
+
145
+ Args:
146
+ message: The initial commit message
147
+
148
+ Returns:
149
+ The edited commit message, or None if editing was cancelled
150
+
151
+ Example:
152
+ >>> edited = edit_commit_message_inplace("feat: add feature")
153
+ >>> # User can edit the message using vi/emacs key bindings
154
+ >>> # Press Esc+Enter or Ctrl+S to submit
155
+ """
156
+ from prompt_toolkit import Application
157
+ from prompt_toolkit.buffer import Buffer
158
+ from prompt_toolkit.document import Document
159
+ from prompt_toolkit.enums import EditingMode
160
+ from prompt_toolkit.key_binding import KeyBindings
161
+ from prompt_toolkit.layout import HSplit, Layout, Window
162
+ from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
163
+ from prompt_toolkit.layout.margins import ScrollbarMargin
164
+ from prompt_toolkit.styles import Style
165
+
166
+ try:
167
+ console.print("\n[info]Edit commit message:[/info]")
168
+ console.print()
169
+
170
+ # Create buffer for text editing
171
+ text_buffer = Buffer(
172
+ document=Document(text=message, cursor_position=0),
173
+ multiline=True,
174
+ enable_history_search=False,
175
+ )
176
+
177
+ # Track submission state
178
+ cancelled = {"value": False}
179
+ submitted = {"value": False}
180
+
181
+ # Create text editor window
182
+ text_window = Window(
183
+ content=BufferControl(
184
+ buffer=text_buffer,
185
+ focus_on_click=True,
186
+ ),
187
+ height=lambda: max(5, message.count("\n") + 3),
188
+ wrap_lines=True,
189
+ right_margins=[ScrollbarMargin()],
190
+ )
191
+
192
+ # Create hint window
193
+ hint_window = Window(
194
+ content=FormattedTextControl(
195
+ text=[("class:hint", " Esc+Enter or Ctrl+S to submit | Ctrl+C to cancel ")],
196
+ ),
197
+ height=1,
198
+ dont_extend_height=True,
199
+ )
200
+
201
+ # Create layout
202
+ root_container = HSplit(
203
+ [
204
+ text_window,
205
+ hint_window,
206
+ ]
207
+ )
208
+
209
+ layout = Layout(root_container, focused_element=text_window)
210
+
211
+ # Create key bindings
212
+ kb = KeyBindings()
213
+
214
+ @kb.add("c-s")
215
+ def _(event):
216
+ """Submit with Ctrl+S."""
217
+ submitted["value"] = True
218
+ event.app.exit()
219
+
220
+ @kb.add("c-c")
221
+ def _(event):
222
+ """Cancel editing."""
223
+ cancelled["value"] = True
224
+ event.app.exit()
225
+
226
+ @kb.add("escape", "enter")
227
+ def _(event):
228
+ """Submit with Esc+Enter."""
229
+ submitted["value"] = True
230
+ event.app.exit()
231
+
232
+ # Create and run application
233
+ custom_style = Style.from_dict(
234
+ {
235
+ "hint": "#888888",
236
+ }
237
+ )
238
+
239
+ app: Application[None] = Application(
240
+ layout=layout,
241
+ key_bindings=kb,
242
+ full_screen=False,
243
+ mouse_support=False,
244
+ editing_mode=EditingMode.VI, # Enable vi key bindings
245
+ style=custom_style,
246
+ )
247
+
248
+ app.run()
249
+
250
+ # Handle result
251
+ if cancelled["value"]:
252
+ console.print("\n[yellow]Edit cancelled.[/yellow]")
253
+ return None
254
+
255
+ if submitted["value"]:
256
+ edited_message = text_buffer.text.strip()
257
+ if not edited_message:
258
+ console.print("[yellow]Commit message cannot be empty. Edit cancelled.[/yellow]")
259
+ return None
260
+ return edited_message
261
+
262
+ return None
263
+
264
+ except (EOFError, KeyboardInterrupt):
265
+ console.print("\n[yellow]Edit cancelled.[/yellow]")
266
+ return None
267
+ except Exception as e:
268
+ logger.error(f"Error during in-place editing: {e}")
269
+ console.print(f"[error]Failed to edit commit message: {e}[/error]")
270
+ return None
gac/workflow_utils.py ADDED
@@ -0,0 +1,131 @@
1
+ import logging
2
+ import tempfile
3
+ from pathlib import Path
4
+
5
+ import click
6
+ from rich.console import Console
7
+
8
+ logger = logging.getLogger(__name__)
9
+ console = Console()
10
+
11
+
12
+ def handle_confirmation_loop(
13
+ commit_message: str,
14
+ conversation_messages: list[dict[str, str]],
15
+ quiet: bool,
16
+ model: str,
17
+ ) -> tuple[str, str, list[dict[str, str]]]:
18
+ from rich.panel import Panel
19
+
20
+ from gac.utils import edit_commit_message_inplace
21
+
22
+ while True:
23
+ response = click.prompt(
24
+ "Proceed with commit above? [y/n/r/e/<feedback>]",
25
+ type=str,
26
+ show_default=False,
27
+ ).strip()
28
+ response_lower = response.lower()
29
+
30
+ if response_lower in ["y", "yes"]:
31
+ return ("yes", commit_message, conversation_messages)
32
+ if response_lower in ["n", "no"]:
33
+ return ("no", commit_message, conversation_messages)
34
+ if response == "":
35
+ continue
36
+ if response_lower in ["e", "edit"]:
37
+ edited_message = edit_commit_message_inplace(commit_message)
38
+ if edited_message:
39
+ commit_message = edited_message
40
+ conversation_messages[-1] = {"role": "assistant", "content": commit_message}
41
+ logger.info("Commit message edited by user")
42
+ console.print("\n[bold green]Edited commit message:[/bold green]")
43
+ console.print(Panel(commit_message, title="Commit Message", border_style="cyan"))
44
+ else:
45
+ console.print("[yellow]Using previous message.[/yellow]")
46
+ console.print(Panel(commit_message, title="Commit Message", border_style="cyan"))
47
+ continue
48
+ if response_lower in ["r", "reroll"]:
49
+ msg = "Please provide an alternative commit message using the same repository context."
50
+ conversation_messages.append({"role": "user", "content": msg})
51
+ console.print("[cyan]Regenerating commit message...[/cyan]")
52
+ return ("regenerate", commit_message, conversation_messages)
53
+
54
+ msg = f"Please revise the commit message based on this feedback: {response}"
55
+ conversation_messages.append({"role": "user", "content": msg})
56
+ console.print(f"[cyan]Regenerating commit message with feedback: {response}[/cyan]")
57
+ return ("regenerate", commit_message, conversation_messages)
58
+
59
+
60
+ def execute_commit(commit_message: str, no_verify: bool) -> None:
61
+ from gac.git import run_git_command
62
+
63
+ commit_args = ["commit", "-m", commit_message]
64
+ if no_verify:
65
+ commit_args.append("--no-verify")
66
+ run_git_command(commit_args)
67
+ logger.info("Commit created successfully")
68
+ console.print("[green]Commit created successfully[/green]")
69
+
70
+
71
+ def check_token_warning(
72
+ prompt_tokens: int,
73
+ warning_limit: int,
74
+ require_confirmation: bool,
75
+ ) -> bool:
76
+ if warning_limit and prompt_tokens > warning_limit:
77
+ console.print(f"[yellow]⚠️ WARNING: Prompt has {prompt_tokens} tokens (limit: {warning_limit})[/yellow]")
78
+ if require_confirmation:
79
+ proceed = click.confirm("Do you want to continue anyway?", default=True)
80
+ if not proceed:
81
+ console.print("[yellow]Aborted due to token limit.[/yellow]")
82
+ return False
83
+ return True
84
+
85
+
86
+ def display_commit_message(commit_message: str, prompt_tokens: int, model: str, quiet: bool) -> None:
87
+ from rich.panel import Panel
88
+
89
+ from gac.ai_utils import count_tokens
90
+
91
+ console.print("[bold green]Generated commit message:[/bold green]")
92
+ console.print(Panel(commit_message, title="Commit Message", border_style="cyan"))
93
+
94
+ if not quiet:
95
+ completion_tokens = count_tokens(commit_message, model)
96
+ total_tokens = prompt_tokens + completion_tokens
97
+ console.print(
98
+ f"[dim]Token usage: {prompt_tokens} prompt + {completion_tokens} completion = {total_tokens} total[/dim]"
99
+ )
100
+
101
+
102
+ def restore_staging(staged_files: list[str], staged_diff: str | None = None) -> None:
103
+ """Restore the git staging area to a previous state.
104
+
105
+ Args:
106
+ staged_files: List of file paths that should be staged
107
+ staged_diff: Optional staged diff to reapply for partial staging
108
+ """
109
+ from gac.git import run_git_command
110
+
111
+ run_git_command(["reset", "HEAD"])
112
+
113
+ if staged_diff:
114
+ temp_path: Path | None = None
115
+ try:
116
+ with tempfile.NamedTemporaryFile("w", delete=False) as tmp:
117
+ tmp.write(staged_diff)
118
+ temp_path = Path(tmp.name)
119
+ run_git_command(["apply", "--cached", str(temp_path)])
120
+ return
121
+ except Exception as e:
122
+ logger.warning(f"Failed to reapply staged diff, falling back to file list: {e}")
123
+ finally:
124
+ if temp_path:
125
+ temp_path.unlink(missing_ok=True)
126
+
127
+ for file_path in staged_files:
128
+ try:
129
+ run_git_command(["add", file_path])
130
+ except Exception as e:
131
+ logger.warning(f"Failed to restore staging for {file_path}: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gac
3
- Version: 2.1.0
3
+ Version: 2.3.0
4
4
  Summary: LLM-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
@@ -25,6 +25,7 @@ Requires-Dist: click>=8.3.0
25
25
  Requires-Dist: halo
26
26
  Requires-Dist: httpcore>=1.0.9
27
27
  Requires-Dist: httpx>=0.28.0
28
+ Requires-Dist: prompt-toolkit>=3.0.36
28
29
  Requires-Dist: pydantic>=2.12.0
29
30
  Requires-Dist: python-dotenv>=1.1.1
30
31
  Requires-Dist: questionary
@@ -107,6 +108,7 @@ uv tool upgrade gac
107
108
  - **Understands intent**: Analyzes code structure, logic, and patterns to understand the "why" behind your changes, not just what changed
108
109
  - **Semantic awareness**: Recognizes refactoring, bug fixes, features, and breaking changes to generate contextually appropriate messages
109
110
  - **Intelligent filtering**: Prioritizes meaningful changes while ignoring generated files, dependencies, and artifacts
111
+ - **Intelligent commit grouping** - Automatically group related changes into multiple logical commits with `--group`
110
112
 
111
113
  ### 📝 **Multiple Message Formats**
112
114
 
@@ -123,7 +125,7 @@ uv tool upgrade gac
123
125
 
124
126
  ### 💻 **Developer Experience**
125
127
 
126
- - **Interactive feedback**: Type `r` to reroll, or directly type your feedback like `make it shorter` or `focus on the bug fix`
128
+ - **Interactive feedback**: Type `r` to reroll, `e` to edit in-place with vi/emacs keybindings, or directly type your feedback like `make it shorter` or `focus on the bug fix`
127
129
  - **One-command workflows**: Complete workflows with flags like `gac -ayp` (stage all, auto-confirm, push)
128
130
  - **Git integration**: Respects pre-commit and lefthook hooks, running them before expensive LLM operations
129
131
 
@@ -146,7 +148,7 @@ git add .
146
148
  # Generate and commit with LLM
147
149
  gac
148
150
 
149
- # Review → y (commit) | n (cancel) | r (reroll) | or type feedback
151
+ # Review → y (commit) | n (cancel) | r (reroll) | e (edit) | or type feedback
150
152
  ```
151
153
 
152
154
  ### Common Commands
@@ -174,6 +176,9 @@ gac -v -s
174
176
  # Quick one-liner for small changes
175
177
  gac -o
176
178
 
179
+ # Group changes into logically related commits
180
+ gac -ag
181
+
177
182
  # Debug what the LLM sees
178
183
  gac --show-prompt
179
184
 
@@ -183,12 +188,17 @@ gac --skip-secret-scan
183
188
 
184
189
  ### Interactive Feedback System
185
190
 
186
- Not happy with the result? You have two options:
191
+ Not happy with the result? You have several options:
187
192
 
188
193
  ```bash
189
194
  # Simple reroll (no feedback)
190
195
  r
191
196
 
197
+ # Edit in-place with rich terminal editing
198
+ e
199
+ # Uses prompt_toolkit for multi-line editing with vi/emacs keybindings
200
+ # Press Esc+Enter or Ctrl+S to submit, Ctrl+C to cancel
201
+
192
202
  # Or just type your feedback directly!
193
203
  make it shorter and focus on the performance improvement
194
204
  use conventional commit format with scope
@@ -197,6 +207,13 @@ explain the security implications
197
207
  # Press Enter on empty input to see the prompt again
198
208
  ```
199
209
 
210
+ The edit feature (`e`) provides rich in-place terminal editing, allowing you to:
211
+
212
+ - **Edit naturally**: Multi-line editing with familiar vi/emacs key bindings
213
+ - **Make quick fixes**: Correct typos, adjust wording, or refine formatting
214
+ - **Add details**: Include information the LLM might have missed
215
+ - **Restructure**: Reorganize bullet points or change the message structure
216
+
200
217
  ---
201
218
 
202
219
  ## Configuration
@@ -1,21 +1,22 @@
1
1
  gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
2
- gac/__version__.py,sha256=bTn7Tm6xpc6WrZ2ANt-S3NGI6Rng6eG5VxYTYs-UWqM,66
3
- gac/ai.py,sha256=iBHeLsqe6iyFj86wbvEosyy4vkjAN1BlLQeqtb_rfmo,4303
4
- gac/ai_utils.py,sha256=094ujZVlbDnHM3HPxiBSCbGi_5MD6bOKCj2SjKVDDK0,7445
5
- gac/cli.py,sha256=SOrSfrlku99O7O8zev5hRVmADAmJ7AIkM7Z0dquuCbQ,5807
2
+ gac/__version__.py,sha256=KHcXxHr9uQK6amU8n-h2x8FjOXkwzFkaiUL62tdw07w,66
3
+ gac/ai.py,sha256=6SQK4axBE0uEbF3eKVTvQtGL9X1TbxoBOrY7NuYIfiM,5009
4
+ gac/ai_utils.py,sha256=reJINfsKlX0HAg5HPlH4ImO6FvibzgRZ0ruG9u1cxa8,8312
5
+ gac/cli.py,sha256=i4VEQeq5k2Rmy8DzqVuJCUyYxSq87x_wLTmH3VgOkyg,5986
6
6
  gac/config.py,sha256=O9n09-sFOqlkf47vieEP7fI5I7uhu1cXn9PUZ5yiYkw,1974
7
7
  gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
8
- gac/constants.py,sha256=Spuqa1ntae0CtNGu-Emxzc_Zz1CipikO3h5BWcUlUW0,9586
8
+ gac/constants.py,sha256=yyvYycIfRJ9SZZIMIhwn1s6yohjcaNM-fGXl_R9w1dI,9586
9
9
  gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
10
10
  gac/errors.py,sha256=ysDIVRCd0YQVTOW3Q6YzdolxCdtkoQCAFf3_jrqbjUY,7916
11
- gac/git.py,sha256=g6tvph50zV-wrTWrxARYXEpl0NeI8-ffFwHoqhp3fSE,8033
12
- gac/init_cli.py,sha256=KvFOvjjyMpdJ3MhJFvXSuYjdfulPA6hCP11YXwjHrqw,8849
13
- gac/language_cli.py,sha256=J4xZNNrMvHamsjK4TCsOVj0lrjYDtLMuHlnTqN0-N_w,3024
14
- gac/main.py,sha256=LJhONOP_w09TE7HOd4T_NiAzmiqemY2N7EZ6biqwVQE,15221
11
+ gac/git.py,sha256=m7EqMYYRNRfD68HbxZD3TUY3DZlzZSdqa38SeLSNb6A,9347
12
+ gac/init_cli.py,sha256=3n6A9FX0atPpO8XMMDypxLTIPxXv-cg_YtRl4yAKUOc,14449
13
+ gac/language_cli.py,sha256=Nl1WKR-o7APOKTg_7T5LoJmg4GaiXnGUzR5XFJayYwI,3050
14
+ gac/main.py,sha256=r5zwAYBBn-qz9kix2Zn5yJ-ac3-42u6HaIoirybOaTQ,28784
15
15
  gac/preprocess.py,sha256=hk2p2X4-xVDvuy-T1VMzMa9k5fTUbhlWDyw89DCf81Q,15379
16
- gac/prompt.py,sha256=HLvsW3YQLdTfw2N9UgjZ0jWckUc1x76V7Kcqjcl8Fsk,28633
17
- gac/security.py,sha256=15Yp6YR8QC4eECJi1BUCkMteh_veZXUbLL6W8qGcDm4,9920
18
- gac/utils.py,sha256=nV42-brIHW_fBg7x855GM8nRrqEBbRzTSweg-GTyGE8,3971
16
+ gac/prompt.py,sha256=ofumb6DmxJceqZLUlUyLE9b7Mwx9BpIEHweKEV9eicw,31841
17
+ gac/security.py,sha256=QT91mBEo2Y7la-aXvKuF2zhWuoOSXb6PWKLJ93kSy2k,9926
18
+ gac/utils.py,sha256=owkUzwJBX8mi0VrP3HKxku5vJj_JlaShzTYwjjsHn-4,8126
19
+ gac/workflow_utils.py,sha256=fc0yPRBeA-7P2WiVPFa7A_NjXTW68UlbUv6_AXVYAzA,5023
19
20
  gac/providers/__init__.py,sha256=pT1xcKoZkPm6BWaxcAQ299-Ca5zZ31kf4DeQYAim9Tw,1367
20
21
  gac/providers/anthropic.py,sha256=VK5d1s1PmBNDwh_x7illQ2CIZIHNIYU28btVfizwQPs,2036
21
22
  gac/providers/cerebras.py,sha256=Ik8lhlsliGJVkgDgqlThfpra9tqbdYQZkaC4eNxRd9w,1648
@@ -36,8 +37,8 @@ gac/providers/streamlake.py,sha256=KAA2ZnpuEI5imzvdWVWUhEBHSP0BMnprKXte6CbwBWY,2
36
37
  gac/providers/synthetic.py,sha256=sRMIJTS9LpcXd9A7qp_ZjZxdqtTKRn9fl1W4YwJZP4c,1855
37
38
  gac/providers/together.py,sha256=1bUIVHfYzcEDw4hQPE8qV6hjc2JNHPv_khVgpk2IJxI,1667
38
39
  gac/providers/zai.py,sha256=kywhhrCfPBu0rElZyb-iENxQxxpVGykvePuL4xrXlaU,2739
39
- gac-2.1.0.dist-info/METADATA,sha256=VYrOHxHKI_6jbenHBBKt3F8IfBNf-n4Vlnf_LUYBuGM,8958
40
- gac-2.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
- gac-2.1.0.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
42
- gac-2.1.0.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
43
- gac-2.1.0.dist-info/RECORD,,
40
+ gac-2.3.0.dist-info/METADATA,sha256=5VIkxFRlLC4NPEGIuZyRUo253XYHdQYt_8uX3gbvjjg,9782
41
+ gac-2.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
+ gac-2.3.0.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
43
+ gac-2.3.0.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
44
+ gac-2.3.0.dist-info/RECORD,,
File without changes