git-copilot-commit 0.2.2__tar.gz → 0.3.1__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 (19) hide show
  1. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.justfile +2 -0
  2. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/PKG-INFO +2 -2
  3. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/pyproject.toml +1 -1
  4. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/cli.py +37 -107
  5. git_copilot_commit-0.3.1/src/git_copilot_commit/prompts/commit-message-generator-prompt.md +58 -0
  6. git_copilot_commit-0.3.1/uv.lock +1174 -0
  7. git_copilot_commit-0.2.2/src/git_copilot_commit/prompts/commit-message-generator-prompt.md +0 -62
  8. git_copilot_commit-0.2.2/uv.lock +0 -334
  9. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.github/workflows/ci.yml +0 -0
  10. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.gitignore +0 -0
  11. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.python-version +0 -0
  12. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/LICENSE +0 -0
  13. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/README.md +0 -0
  14. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/__init__.py +0 -0
  15. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/git.py +0 -0
  16. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/py.typed +0 -0
  17. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/settings.py +0 -0
  18. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/version.py +0 -0
  19. {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/vhs/demo.vhs +0 -0
@@ -49,6 +49,8 @@ release version:
49
49
  #!/usr/bin/env bash
50
50
  set -euo pipefail
51
51
 
52
+ version="{{version}}"
53
+
52
54
  echo "Pushing commit and tag for $version..."
53
55
  git push
54
56
  git push origin "$version"
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-copilot-commit
3
- Version: 0.2.2
3
+ Version: 0.3.1
4
4
  Summary: Automatically generate and commit changes using copilot
5
5
  Author-email: Dheepak Krishnamurthy <1813121+kdheepak@users.noreply.github.com>
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.12
8
+ Requires-Dist: litellm>=1.75.4
8
9
  Requires-Dist: platformdirs>=4.0.0
9
- Requires-Dist: pycopilot>=0.1.7
10
10
  Requires-Dist: rich>=14.0.0
11
11
  Requires-Dist: typer>=0.16.0
12
12
  Description-Content-Type: text/markdown
@@ -8,10 +8,10 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [
11
- "pycopilot>=0.1.7",
12
11
  "rich>=14.0.0",
13
12
  "typer>=0.16.0",
14
13
  "platformdirs>=4.0.0",
14
+ "litellm>=1.75.4",
15
15
  ]
16
16
 
17
17
  [project.scripts]
@@ -3,17 +3,14 @@ git-copilot-commit - AI-powered Git commit assistant
3
3
  """
4
4
 
5
5
  import rich.terminal_theme
6
- import sys
7
6
  import typer
8
7
  from rich.console import Console
9
8
  from rich.prompt import Confirm
10
9
  from rich.panel import Panel
11
- from rich.table import Table
12
10
  import rich
13
11
  from pathlib import Path
14
12
 
15
- from pycopilot.copilot import Copilot, CopilotAPIError # type: ignore
16
- from pycopilot.auth import Authentication
13
+ from litellm import completion
17
14
  from .git import GitRepository, GitError, NotAGitRepositoryError
18
15
  from .settings import Settings
19
16
  from .version import __version__
@@ -87,6 +84,29 @@ def load_system_prompt() -> str:
87
84
  raise typer.Exit(1)
88
85
 
89
86
 
87
+ def ask(prompt, model) -> str:
88
+ response = completion(
89
+ model=model,
90
+ messages=[
91
+ {"role": "system", "content": load_system_prompt()},
92
+ {"role": "user", "content": prompt},
93
+ ],
94
+ extra_headers={
95
+ "editor-version": "vscode/1.85.1",
96
+ "Copilot-Integration-Id": "vscode-chat",
97
+ },
98
+ )
99
+ text = response.choices[0].message.content
100
+ text = text.strip()
101
+ # Remove triple backticks if they wrap the entire text
102
+ if text.startswith("```") and text.endswith("```"):
103
+ text = text[3:-3].strip()
104
+ # Otherwise remove single backticks if they wrap the entire text
105
+ elif text.startswith("`") and text.endswith("`"):
106
+ text = text[1:-1].strip()
107
+ return text
108
+
109
+
90
110
  def generate_commit_message(
91
111
  repo: GitRepository, model: str | None = None, context: str = ""
92
112
  ) -> str:
@@ -99,9 +119,6 @@ def generate_commit_message(
99
119
  console.print("[red]No staged changes to commit.[/red]")
100
120
  raise typer.Exit()
101
121
 
102
- system_prompt = load_system_prompt()
103
- client = Copilot(system_prompt=system_prompt)
104
-
105
122
  prompt_parts = [
106
123
  "`git status`:\n",
107
124
  f"```\n{status.get_porcelain_output()}\n```",
@@ -116,11 +133,19 @@ def generate_commit_message(
116
133
 
117
134
  prompt = "\n".join(prompt_parts)
118
135
 
136
+ if model is None:
137
+ model = "github_copilot/gpt-4"
138
+
139
+ if not model.startswith("github_copilot/"):
140
+ model = f"github_copilot/{model}"
141
+
119
142
  try:
120
- client.reset()
121
- response = client.ask(prompt, model=model) if model else client.ask(prompt)
122
- return response.content
143
+ return ask(prompt, model=model)
123
144
  except Exception as _:
145
+ console.print(
146
+ "Prompt failed, falling back to simpler commit message generation."
147
+ )
148
+
124
149
  fallback_prompt_parts = [
125
150
  "`git status`:\n",
126
151
  f"```\n{status.get_porcelain_output()}\n```",
@@ -137,13 +162,7 @@ def generate_commit_message(
137
162
 
138
163
  fallback_prompt = "\n".join(fallback_prompt_parts)
139
164
 
140
- client.reset()
141
- response = (
142
- client.ask(fallback_prompt, model=model)
143
- if model
144
- else client.ask(fallback_prompt)
145
- )
146
- return response.content
165
+ return ask(fallback_prompt, model=model)
147
166
 
148
167
 
149
168
  @app.command()
@@ -221,9 +240,7 @@ def commit(
221
240
  ):
222
241
  commit_message = generate_commit_message(repo, model, context=context)
223
242
 
224
- console.print(
225
- "[yellow]Generated commit message based on [bold]`git diff --staged`[/] ...[/yellow]"
226
- )
243
+ console.print("[yellow]Generated commit message.[/yellow]")
227
244
 
228
245
  # Display commit message
229
246
  console.print(
@@ -275,47 +292,6 @@ def commit(
275
292
  console.print(f"[green]✓ Successfully committed: {commit_sha[:8]}[/green]")
276
293
 
277
294
 
278
- @app.command()
279
- def authenticate():
280
- """Autheticate with GitHub Copilot."""
281
- Authentication().auth()
282
-
283
-
284
- @app.command()
285
- def models():
286
- """List models available for chat in a table."""
287
- models = Copilot().models
288
-
289
- console = Console()
290
- table = Table(title="Available Models")
291
-
292
- table.add_column("ID", style="cyan", no_wrap=True)
293
- table.add_column("Name", style="magenta")
294
- table.add_column("Vendor", style="green")
295
- table.add_column("Version", style="yellow")
296
- table.add_column("Family", style="white")
297
- table.add_column("Max Tokens", style="white")
298
- table.add_column("Streaming", style="white")
299
-
300
- for model in models:
301
- capabilities = model.get("capabilities", {})
302
- family = capabilities.get("family", "N/A")
303
- max_tokens = capabilities.get("limits", {}).get("max_output_tokens", "N/A")
304
- streaming = capabilities.get("supports", {}).get("streaming", False)
305
-
306
- table.add_row(
307
- model.get("id", "N/A"),
308
- model.get("name", "N/A"),
309
- model.get("vendor", "N/A"),
310
- model.get("version", "N/A"),
311
- family,
312
- str(max_tokens),
313
- str(streaming),
314
- )
315
-
316
- console.print(table)
317
-
318
-
319
295
  @app.command()
320
296
  def config(
321
297
  set_default_model: str | None = typer.Option(
@@ -347,51 +323,5 @@ def config(
347
323
  console.print(f"Config file: [dim]{settings.config_file}[/dim]")
348
324
 
349
325
 
350
- @app.command()
351
- def echo(
352
- model: str | None = typer.Option(
353
- None, "--model", "-m", help="Model to use for generating commit message"
354
- ),
355
- ):
356
- """
357
- Generate commit message from stdin input (useful for pipes).
358
- """
359
- # Read from stdin
360
- input_text = sys.stdin.read()
361
-
362
- if not input_text.strip():
363
- console.print("[red]Error: No input provided via stdin[/red]")
364
- raise typer.Exit(1)
365
-
366
- # Load settings and use default model if none provided
367
- settings = Settings()
368
- if model is None:
369
- model = settings.default_model
370
-
371
- # Load system prompt and create client
372
- system_prompt = load_system_prompt()
373
- client = Copilot(system_prompt=system_prompt)
374
-
375
- # Generate commit message from the input
376
- prompt = f"""
377
- `git diff --staged`:
378
-
379
- ```
380
- {input_text.strip()}
381
- ```
382
-
383
- Generate a conventional commit message based on the input above:"""
384
-
385
- try:
386
- response = client.ask(prompt, model=model) if model else client.ask(prompt)
387
- # Print the commit message directly to stdout (no rich formatting for pipes)
388
- import builtins
389
-
390
- builtins.print(response.content)
391
- except CopilotAPIError as e:
392
- console.print(f"[red]Error generating commit message: {e}[/red]")
393
- raise typer.Exit(1)
394
-
395
-
396
326
  if __name__ == "__main__":
397
327
  app()
@@ -0,0 +1,58 @@
1
+ # Commit Message Generator System Prompt
2
+
3
+ You are a Git commit message assistant trained to write a single clear, structured, and informative commit message following the Conventional Commits specification.
4
+
5
+ Your task is to generate a commit message in the [Conventional Commits](https://www.conventionalcommits.org/) format based on both inputs.
6
+
7
+ ## Output Format
8
+
9
+ <type>(<optional scope>): <description>
10
+
11
+ - Do not include a body or footer.
12
+ - Do not wrap the message in backticks or code blocks.
13
+ - Keep the title line ≤72 characters.
14
+
15
+ ## `<type>`
16
+
17
+ - `feat`: New feature
18
+ - `fix`: Bug fix
19
+ - `docs`: Documentation changes
20
+ - `style`: Code formatting (no logic changes)
21
+ - `refactor`: Code restructuring (no behavior changes)
22
+ - `perf`: Performance improvements
23
+ - `test`: Adding or updating tests
24
+ - `chore`: Maintenance tasks (e.g., CI/CD, dependencies)
25
+ - `revert`: Revert of a previous commit
26
+
27
+ ## `(<optional scope>)`
28
+
29
+ - Lowercase, single word or hyphenated phrase
30
+ - Represents the affected area, module, or file
31
+ - Use broad area if multiple related files are affected
32
+
33
+ ## `<description>`
34
+
35
+ - Use imperative mood ("remove" not "removed")
36
+ - Focus on **what** changed, not why or how
37
+ - Be concise and specific
38
+ - Use abbreviations (e.g., "config" not "configuration")
39
+
40
+ ---
41
+
42
+ ## Do Not
43
+
44
+ - Do not speculate or infer what the diff is doing
45
+ - Do not use vague phrases ("made changes", "updated code")
46
+ - Do not use past tense ("added", "removed")
47
+ - Do not use terms like "unused", "duplicate", or "deprecated" unless explicitly stated by the user or clearly shown in the diff.
48
+ - Do not explain implementation or reasoning ("to fix bug", "because of issue")
49
+ - Do not guess purpose based on intuition or incomplete file context
50
+ - Do not wrap the response in single backticks or triple backticks or code blocks
51
+
52
+ ---
53
+
54
+ The user will provide a Git diff, a list of modified files, or a short description of changes.
55
+
56
+ Generate a single, short, clear and structured Conventional Commit message following the above rules. If multiple changes are detected, prioritize the most important changes in a single commit message. Do not add any body or footer. You can only give one reply for each conversation.
57
+
58
+ Return the commit message as the output without any additional text, explanations, or formatting markers.