git-copilot-commit 0.1.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.
- git_copilot_commit-0.1.0/.gitignore +10 -0
- git_copilot_commit-0.1.0/.python-version +1 -0
- git_copilot_commit-0.1.0/LICENSE +19 -0
- git_copilot_commit-0.1.0/PKG-INFO +11 -0
- git_copilot_commit-0.1.0/README.md +0 -0
- git_copilot_commit-0.1.0/pyproject.toml +22 -0
- git_copilot_commit-0.1.0/src/git_copilot_commit/__init__.py +0 -0
- git_copilot_commit-0.1.0/src/git_copilot_commit/cli.py +369 -0
- git_copilot_commit-0.1.0/src/git_copilot_commit/git.py +368 -0
- git_copilot_commit-0.1.0/src/git_copilot_commit/py.typed +0 -0
- git_copilot_commit-0.1.0/uv.lock +343 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2025 Dheepak Krishnamurthy
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: git-copilot-commit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Automatically generate and commit changes using copilot
|
|
5
|
+
Author-email: Dheepak Krishnamurthy <1813121+kdheepak@users.noreply.github.com>
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Requires-Dist: pycopilot>=0.1.1
|
|
9
|
+
Requires-Dist: rich>=14.0.0
|
|
10
|
+
Requires-Dist: typer>=0.16.0
|
|
11
|
+
Requires-Dist: xdg-base-dirs>=6.0.2
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "git-copilot-commit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Automatically generate and commit changes using copilot"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Dheepak Krishnamurthy", email = "1813121+kdheepak@users.noreply.github.com" },
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"pycopilot>=0.1.1",
|
|
12
|
+
"rich>=14.0.0",
|
|
13
|
+
"typer>=0.16.0",
|
|
14
|
+
"xdg-base-dirs>=6.0.2",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
git-copilot-commit = "git_copilot_commit.cli:app"
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["hatchling"]
|
|
22
|
+
build-backend = "hatchling.build"
|
|
File without changes
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
git-copilot-commit - AI-powered Git commit assistant
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.prompt import Confirm
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from pycopilot.copilot import Copilot
|
|
12
|
+
from pycopilot.auth import Authentication
|
|
13
|
+
from .git import GitRepository, GitError, NotAGitRepositoryError, GitStatus
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
app = typer.Typer(help=__doc__, add_completion=False)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.callback(invoke_without_command=True)
|
|
20
|
+
def main(ctx: typer.Context):
|
|
21
|
+
"""
|
|
22
|
+
Automatically commit changes in the current git repository.
|
|
23
|
+
"""
|
|
24
|
+
if ctx.invoked_subcommand is None:
|
|
25
|
+
# Show help when no command is provided
|
|
26
|
+
print(ctx.get_help())
|
|
27
|
+
raise typer.Exit()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def display_file_status(status: GitStatus) -> None:
|
|
31
|
+
"""Display file status in a rich table."""
|
|
32
|
+
if not status.files:
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
table = Table(title="Git Status")
|
|
36
|
+
table.add_column("Status", style="yellow", width=8)
|
|
37
|
+
table.add_column("File", style="white")
|
|
38
|
+
|
|
39
|
+
# Group files by status
|
|
40
|
+
staged = status.staged_files
|
|
41
|
+
unstaged = status.unstaged_files
|
|
42
|
+
untracked = status.untracked_files
|
|
43
|
+
|
|
44
|
+
if staged:
|
|
45
|
+
table.add_row("[green]Staged[/green]", "", style="dim")
|
|
46
|
+
for file in staged:
|
|
47
|
+
table.add_row(f" {file.staged_status}", file.path)
|
|
48
|
+
|
|
49
|
+
if unstaged:
|
|
50
|
+
table.add_row("[yellow]Unstaged[/yellow]", "", style="dim")
|
|
51
|
+
for file in unstaged:
|
|
52
|
+
table.add_row(f" {file.status}", file.path)
|
|
53
|
+
|
|
54
|
+
if untracked:
|
|
55
|
+
table.add_row("[red]Untracked[/red]", "", style="dim")
|
|
56
|
+
for file in untracked:
|
|
57
|
+
table.add_row(" ?", file.path)
|
|
58
|
+
|
|
59
|
+
console.print(table)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def generate_commit_message(repo: GitRepository, status: GitStatus) -> str:
|
|
63
|
+
"""Generate a conventional commit message using Copilot API."""
|
|
64
|
+
|
|
65
|
+
# Get recent commits for context
|
|
66
|
+
recent_commits = repo.get_recent_commits(limit=5)
|
|
67
|
+
recent_commits_text = "\n".join([f"- {msg}" for _, msg in recent_commits])
|
|
68
|
+
|
|
69
|
+
client = Copilot(
|
|
70
|
+
system_prompt="""
|
|
71
|
+
|
|
72
|
+
You are a Git commit message assistant trained to write a single clear, structured, and informative commit message following the Conventional Commits specification based on the provided `git diff --staged` output.
|
|
73
|
+
|
|
74
|
+
Output format: Provide only the commit message without any additional text, explanations, or formatting markers.
|
|
75
|
+
|
|
76
|
+
The guidelines for the commit messages are as follows:
|
|
77
|
+
|
|
78
|
+
1. Format
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
<type>[optional scope]: <description>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- The first line (title) should be at most 72 characters long.
|
|
85
|
+
- If the natural description exceeds 72 characters, prioritize the most important aspect.
|
|
86
|
+
- Use abbreviations when appropriate: `config` not `configuration`.
|
|
87
|
+
- The body (if present) should be wrapped at 100 characters per line.
|
|
88
|
+
|
|
89
|
+
2. Valid Commit Types:
|
|
90
|
+
|
|
91
|
+
- `feat`: A new feature
|
|
92
|
+
- `fix`: A bug fix
|
|
93
|
+
- `docs`: Documentation changes
|
|
94
|
+
- `style`: Code formatting (no logic changes)
|
|
95
|
+
- `refactor`: Code restructuring (no behavior changes)
|
|
96
|
+
- `perf`: Performance improvements
|
|
97
|
+
- `test`: Adding or updating tests
|
|
98
|
+
- `chore`: Maintenance tasks (e.g., tooling, CI/CD, dependencies)
|
|
99
|
+
- `revert`: Reverting previous changes
|
|
100
|
+
|
|
101
|
+
3. Scope (Optional but encouraged):
|
|
102
|
+
|
|
103
|
+
- Enclose in parentheses, e.g., feat(auth): add login endpoint.
|
|
104
|
+
- Use the affected module, component, or area: `auth`, `api`, `ui`, `database`, `config`.
|
|
105
|
+
- For multiple files in same area, use the broader scope: `feat(auth): add login and logout endpoints`.
|
|
106
|
+
- For single files, you may use filename: `fix(user-service): handle null email validation`.
|
|
107
|
+
- Scope should be a single word or hyphenated phrase describing the affected module.
|
|
108
|
+
|
|
109
|
+
4. Description:
|
|
110
|
+
|
|
111
|
+
- Use imperative mood (e.g., "add feature" instead of "added" or "adds").
|
|
112
|
+
- Be concise yet informative.
|
|
113
|
+
- Focus on the primary change, not all details.
|
|
114
|
+
- Do not make assumptions about why the change was made or how it works.
|
|
115
|
+
- Do not say "improving code readability" or similar; focus on just the change itself.
|
|
116
|
+
|
|
117
|
+
5. Analyzing Git Diffs:
|
|
118
|
+
|
|
119
|
+
- Focus on the logical change, not individual line modifications.
|
|
120
|
+
- Group related file changes under one logical scope.
|
|
121
|
+
- Identify the primary purpose of the change set.
|
|
122
|
+
- If changes span multiple unrelated areas, focus on the most significant one.
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
|
|
126
|
+
✅ Good Commit Messages:
|
|
127
|
+
|
|
128
|
+
- feat(api): add user authentication with JWT
|
|
129
|
+
- fix(database): handle connection retries properly
|
|
130
|
+
- docs(readme): update installation instructions
|
|
131
|
+
- refactor(utils): simplify date parsing logic
|
|
132
|
+
- chore(deps): update dependencies to latest versions
|
|
133
|
+
- feat(auth): implement OAuth2 integration
|
|
134
|
+
- fix(payments): resolve double-charging bug in subscription renewal
|
|
135
|
+
- refactor(database): extract query builder into separate module
|
|
136
|
+
- chore(ci): add automated security scanning to pipeline
|
|
137
|
+
- docs(api): add OpenAPI specifications for user endpoints
|
|
138
|
+
|
|
139
|
+
❌ Strongly Avoid:
|
|
140
|
+
|
|
141
|
+
- Vague descriptions: "fixed bug", "updated code", "made changes"
|
|
142
|
+
- Past tense: "added feature", "fixed issue"
|
|
143
|
+
- Explanations of why: "to improve performance", "because users requested"
|
|
144
|
+
- Implementation details: "using React hooks", "with try-catch blocks"
|
|
145
|
+
- Not in imperative mood: "new feature", "updates stuff"
|
|
146
|
+
|
|
147
|
+
Given a Git diff, a list of modified files, or a short description of changes,
|
|
148
|
+
generate a single clear and structured Conventional Commit message following the above rules.
|
|
149
|
+
If multiple changes are detected, prioritize the most important changes in a single commit message.
|
|
150
|
+
Do not add any body or footer.
|
|
151
|
+
You can only give one reply for each conversation turn.
|
|
152
|
+
|
|
153
|
+
Avoid wrapping the whole response in triple backticks.
|
|
154
|
+
"""
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
prompt = f"""Recent commits:
|
|
158
|
+
{recent_commits_text}
|
|
159
|
+
|
|
160
|
+
`git status`:
|
|
161
|
+
```
|
|
162
|
+
{status.get_porcelain_output()}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`git diff --staged`:
|
|
166
|
+
```
|
|
167
|
+
{status.staged_diff}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Generate a conventional commit message:"""
|
|
171
|
+
|
|
172
|
+
response = client.ask(prompt)
|
|
173
|
+
return response.content
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@app.command()
|
|
177
|
+
def commit(
|
|
178
|
+
all_files: bool = typer.Option(
|
|
179
|
+
False, "--all", "-a", help="Stage all files before committing"
|
|
180
|
+
),
|
|
181
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show verbose output"),
|
|
182
|
+
):
|
|
183
|
+
"""
|
|
184
|
+
Automatically commit changes in the current git repository.
|
|
185
|
+
"""
|
|
186
|
+
try:
|
|
187
|
+
repo = GitRepository()
|
|
188
|
+
except NotAGitRepositoryError:
|
|
189
|
+
console.print("[red]Error: Not in a git repository[/red]")
|
|
190
|
+
raise typer.Exit(1)
|
|
191
|
+
|
|
192
|
+
# Get initial status
|
|
193
|
+
status = repo.get_status()
|
|
194
|
+
|
|
195
|
+
if not status.files:
|
|
196
|
+
console.print("[yellow]No changes to commit.[/yellow]")
|
|
197
|
+
raise typer.Exit()
|
|
198
|
+
|
|
199
|
+
# Display current status
|
|
200
|
+
if verbose:
|
|
201
|
+
display_file_status(status)
|
|
202
|
+
|
|
203
|
+
# Handle staging based on options
|
|
204
|
+
if all_files:
|
|
205
|
+
repo.stage_files() # Stage all files
|
|
206
|
+
console.print("[green]Staged all files.[/green]")
|
|
207
|
+
else:
|
|
208
|
+
# Check if we need to stage files
|
|
209
|
+
if status.has_unstaged_changes:
|
|
210
|
+
if Confirm.ask("Stage modified files?"):
|
|
211
|
+
repo.stage_modified()
|
|
212
|
+
console.print("[green]Staged modified files.[/green]")
|
|
213
|
+
else:
|
|
214
|
+
raise typer.Exit()
|
|
215
|
+
if status.has_untracked_files:
|
|
216
|
+
if Confirm.ask("Stage untracked files?"):
|
|
217
|
+
repo.stage_files()
|
|
218
|
+
console.print("[green]Staged untracked files.[/green]")
|
|
219
|
+
else:
|
|
220
|
+
raise typer.Exit()
|
|
221
|
+
|
|
222
|
+
# Refresh status after staging
|
|
223
|
+
status = repo.get_status()
|
|
224
|
+
|
|
225
|
+
if not status.has_staged_changes:
|
|
226
|
+
console.print("[yellow]No staged changes to commit.[/yellow]")
|
|
227
|
+
raise typer.Exit()
|
|
228
|
+
|
|
229
|
+
# Generate or use provided commit message
|
|
230
|
+
console.print("[cyan]Generating commit message...[/cyan]")
|
|
231
|
+
with console.status("[cyan]Generating commit message using Copilot API...[/cyan]"):
|
|
232
|
+
commit_message = generate_commit_message(repo, status)
|
|
233
|
+
|
|
234
|
+
# Display commit message
|
|
235
|
+
console.print(Panel(commit_message, title="Commit Message", border_style="green"))
|
|
236
|
+
|
|
237
|
+
# Show what will be committed in verbose mode
|
|
238
|
+
if verbose:
|
|
239
|
+
console.print("\n[bold]Changes to be committed:[/bold]")
|
|
240
|
+
for file in status.staged_files:
|
|
241
|
+
console.print(f" {file.staged_status} {file.path}")
|
|
242
|
+
|
|
243
|
+
# Confirm commit or edit message
|
|
244
|
+
choice = typer.prompt(
|
|
245
|
+
"Choose action: (c)ommit, (e)dit message, (q)uit",
|
|
246
|
+
default="c",
|
|
247
|
+
show_default=True,
|
|
248
|
+
).lower()
|
|
249
|
+
|
|
250
|
+
if choice == "q":
|
|
251
|
+
console.print("Commit cancelled.")
|
|
252
|
+
raise typer.Exit()
|
|
253
|
+
elif choice == "e":
|
|
254
|
+
# Use git's built-in editor with generated message as template
|
|
255
|
+
console.print("[cyan]Opening git editor...[/cyan]")
|
|
256
|
+
try:
|
|
257
|
+
commit_sha = repo.commit(commit_message, use_editor=True)
|
|
258
|
+
except GitError as e:
|
|
259
|
+
console.print(f"[red]Commit failed: {e}[/red]")
|
|
260
|
+
raise typer.Exit(1)
|
|
261
|
+
elif choice == "c":
|
|
262
|
+
# Commit with generated message
|
|
263
|
+
try:
|
|
264
|
+
commit_sha = repo.commit(commit_message)
|
|
265
|
+
except GitError as e:
|
|
266
|
+
console.print(f"[red]Commit failed: {e}[/red]")
|
|
267
|
+
raise typer.Exit(1)
|
|
268
|
+
else:
|
|
269
|
+
console.print("Invalid choice. Commit cancelled.")
|
|
270
|
+
raise typer.Exit()
|
|
271
|
+
|
|
272
|
+
# Show success message
|
|
273
|
+
console.print(f"[green]✓ Successfully committed: {commit_sha[:8]}[/green]")
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def handle_interactive_staging(repo: GitRepository, status: GitStatus) -> None:
|
|
277
|
+
"""Handle interactive file staging."""
|
|
278
|
+
# Combine all files that can be staged
|
|
279
|
+
stageable_files = [f for f in status.files if not f.is_staged]
|
|
280
|
+
|
|
281
|
+
if not stageable_files:
|
|
282
|
+
console.print("[yellow]No files to stage.[/yellow]")
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
table = Table(title="Select files to stage")
|
|
286
|
+
table.add_column("Index", style="cyan", width=6)
|
|
287
|
+
table.add_column("Status", style="yellow", width=8)
|
|
288
|
+
table.add_column("File", style="white")
|
|
289
|
+
|
|
290
|
+
for i, file in enumerate(stageable_files, 1):
|
|
291
|
+
status_char = file.status if not file.is_untracked else "?"
|
|
292
|
+
table.add_row(str(i), status_char, file.path)
|
|
293
|
+
|
|
294
|
+
console.print(table)
|
|
295
|
+
|
|
296
|
+
selection = (
|
|
297
|
+
console.input(
|
|
298
|
+
"\nEnter file numbers to stage (comma-separated), 'all', or 'quit': "
|
|
299
|
+
)
|
|
300
|
+
.strip()
|
|
301
|
+
.lower()
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if selection == "quit":
|
|
305
|
+
return
|
|
306
|
+
elif selection == "all":
|
|
307
|
+
repo.stage_files([f.path for f in stageable_files])
|
|
308
|
+
console.print(f"[green]Staged {len(stageable_files)} files.[/green]")
|
|
309
|
+
else:
|
|
310
|
+
try:
|
|
311
|
+
indices = [int(x.strip()) - 1 for x in selection.split(",")]
|
|
312
|
+
files_to_stage = [
|
|
313
|
+
stageable_files[i].path
|
|
314
|
+
for i in indices
|
|
315
|
+
if 0 <= i < len(stageable_files)
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
if files_to_stage:
|
|
319
|
+
repo.stage_files(files_to_stage)
|
|
320
|
+
console.print(f"[green]Staged {len(files_to_stage)} files.[/green]")
|
|
321
|
+
else:
|
|
322
|
+
console.print("[yellow]No valid files selected.[/yellow]")
|
|
323
|
+
except (ValueError, IndexError):
|
|
324
|
+
console.print("[red]Invalid selection.[/red]")
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
@app.command()
|
|
328
|
+
def authenticate():
|
|
329
|
+
"""Autheticate with GitHub Copilot."""
|
|
330
|
+
Authentication().auth()
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@app.command()
|
|
334
|
+
def models():
|
|
335
|
+
"""List models available for chat in a Rich table."""
|
|
336
|
+
models = Copilot().models
|
|
337
|
+
|
|
338
|
+
console = Console()
|
|
339
|
+
table = Table(title="Available Models")
|
|
340
|
+
|
|
341
|
+
table.add_column("ID", style="cyan", no_wrap=True)
|
|
342
|
+
table.add_column("Name", style="magenta")
|
|
343
|
+
table.add_column("Vendor", style="green")
|
|
344
|
+
table.add_column("Version", style="yellow")
|
|
345
|
+
table.add_column("Family", style="white")
|
|
346
|
+
table.add_column("Max Tokens", style="white")
|
|
347
|
+
table.add_column("Streaming", style="white")
|
|
348
|
+
|
|
349
|
+
for model in models:
|
|
350
|
+
capabilities = model.get("capabilities", {})
|
|
351
|
+
family = capabilities.get("family", "N/A")
|
|
352
|
+
max_tokens = capabilities.get("limits", {}).get("max_output_tokens", "N/A")
|
|
353
|
+
streaming = capabilities.get("supports", {}).get("streaming", False)
|
|
354
|
+
|
|
355
|
+
table.add_row(
|
|
356
|
+
model.get("id", "N/A"),
|
|
357
|
+
model.get("name", "N/A"),
|
|
358
|
+
model.get("vendor", "N/A"),
|
|
359
|
+
model.get("version", "N/A"),
|
|
360
|
+
family,
|
|
361
|
+
str(max_tokens),
|
|
362
|
+
str(streaming),
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
console.print(table)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
if __name__ == "__main__":
|
|
369
|
+
app()
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Tuple, Optional, Union
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GitError(Exception):
|
|
9
|
+
"""Base exception for git-related errors."""
|
|
10
|
+
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class NotAGitRepositoryError(GitError):
|
|
15
|
+
"""Raised when not in a git repository."""
|
|
16
|
+
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GitCommandError(GitError):
|
|
21
|
+
"""Raised when a git command fails."""
|
|
22
|
+
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FileStatus(Enum):
|
|
27
|
+
"""Git file status codes."""
|
|
28
|
+
|
|
29
|
+
MODIFIED = "M"
|
|
30
|
+
ADDED = "A"
|
|
31
|
+
DELETED = "D"
|
|
32
|
+
RENAMED = "R"
|
|
33
|
+
COPIED = "C"
|
|
34
|
+
UNMERGED = "U"
|
|
35
|
+
UNTRACKED = "?"
|
|
36
|
+
IGNORED = "!"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class GitFile:
|
|
41
|
+
"""Represents a file in git status."""
|
|
42
|
+
|
|
43
|
+
path: str
|
|
44
|
+
status: str
|
|
45
|
+
staged_status: str
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def is_staged(self) -> bool:
|
|
49
|
+
"""Check if file has staged changes."""
|
|
50
|
+
return self.staged_status != " " and self.staged_status != "?"
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def is_modified(self) -> bool:
|
|
54
|
+
"""Check if file is modified."""
|
|
55
|
+
return self.status == "M" or self.staged_status == "M"
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def is_untracked(self) -> bool:
|
|
59
|
+
"""Check if file is untracked."""
|
|
60
|
+
return self.staged_status == "?" and self.status == "?"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class GitStatus:
|
|
65
|
+
"""Structured representation of git status."""
|
|
66
|
+
|
|
67
|
+
files: List[GitFile]
|
|
68
|
+
staged_diff: str
|
|
69
|
+
unstaged_diff: str
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def has_staged_changes(self) -> bool:
|
|
73
|
+
"""Check if there are any staged changes."""
|
|
74
|
+
return bool(self.staged_diff.strip())
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def has_unstaged_changes(self) -> bool:
|
|
78
|
+
"""Check if there are any unstaged changes."""
|
|
79
|
+
return bool(self.unstaged_diff.strip())
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def has_untracked_files(self) -> bool:
|
|
83
|
+
"""Check if there are any untracked files."""
|
|
84
|
+
return any(f.is_untracked for f in self.files)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def staged_files(self) -> List[GitFile]:
|
|
88
|
+
"""Get list of files with staged changes."""
|
|
89
|
+
return [f for f in self.files if f.is_staged]
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def unstaged_files(self) -> List[GitFile]:
|
|
93
|
+
"""Get list of files with unstaged changes."""
|
|
94
|
+
return [f for f in self.files if not f.is_staged and not f.is_untracked]
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def untracked_files(self) -> List[GitFile]:
|
|
98
|
+
"""Get list of untracked files."""
|
|
99
|
+
return [f for f in self.files if f.is_untracked]
|
|
100
|
+
|
|
101
|
+
def get_porcelain_output(self) -> str:
|
|
102
|
+
"""Get the original porcelain output format."""
|
|
103
|
+
lines = []
|
|
104
|
+
for file in self.files:
|
|
105
|
+
lines.append(f"{file.staged_status}{file.status} {file.path}")
|
|
106
|
+
return "\n".join(lines)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class GitRepository:
|
|
110
|
+
"""Encapsulates git repository operations."""
|
|
111
|
+
|
|
112
|
+
def __init__(self, repo_path: Optional[Path] = None, timeout: int = 30):
|
|
113
|
+
"""
|
|
114
|
+
Initialize GitRepository.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
repo_path: Path to git repository. Defaults to current directory.
|
|
118
|
+
timeout: Timeout for git commands in seconds.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
NotAGitRepositoryError: If the path is not a git repository.
|
|
122
|
+
"""
|
|
123
|
+
self.repo_path = repo_path or Path.cwd()
|
|
124
|
+
self.timeout = timeout
|
|
125
|
+
self._validate_git_repo()
|
|
126
|
+
|
|
127
|
+
def _validate_git_repo(self) -> None:
|
|
128
|
+
"""Ensure we're in a git repository."""
|
|
129
|
+
try:
|
|
130
|
+
self._run_git_command(["rev-parse", "--git-dir"])
|
|
131
|
+
except GitCommandError:
|
|
132
|
+
raise NotAGitRepositoryError(f"{self.repo_path} is not a git repository")
|
|
133
|
+
|
|
134
|
+
def _run_git_command(
|
|
135
|
+
self, args: List[str], check: bool = True
|
|
136
|
+
) -> subprocess.CompletedProcess:
|
|
137
|
+
"""
|
|
138
|
+
Run a git command and return the result.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
args: Git command arguments (without 'git' prefix).
|
|
142
|
+
check: Whether to raise exception on non-zero exit code.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
CompletedProcess instance.
|
|
146
|
+
|
|
147
|
+
Raises:
|
|
148
|
+
GitCommandError: If command fails and check=True.
|
|
149
|
+
"""
|
|
150
|
+
cmd = ["git"] + args
|
|
151
|
+
try:
|
|
152
|
+
result = subprocess.run(
|
|
153
|
+
cmd,
|
|
154
|
+
cwd=self.repo_path,
|
|
155
|
+
capture_output=True,
|
|
156
|
+
text=True,
|
|
157
|
+
timeout=self.timeout,
|
|
158
|
+
check=check,
|
|
159
|
+
)
|
|
160
|
+
return result
|
|
161
|
+
except subprocess.CalledProcessError as e:
|
|
162
|
+
raise GitCommandError(f"Git command failed: {' '.join(cmd)}\n{e.stderr}")
|
|
163
|
+
except subprocess.TimeoutExpired:
|
|
164
|
+
raise GitCommandError(f"Git command timed out: {' '.join(cmd)}")
|
|
165
|
+
|
|
166
|
+
def get_status(self) -> GitStatus:
|
|
167
|
+
"""
|
|
168
|
+
Get comprehensive git status information.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
GitStatus object with all status information.
|
|
172
|
+
"""
|
|
173
|
+
# Get porcelain status
|
|
174
|
+
status_result = self._run_git_command(["status", "--porcelain"])
|
|
175
|
+
|
|
176
|
+
# Get staged diff
|
|
177
|
+
staged_diff_result = self._run_git_command(["diff", "--staged"])
|
|
178
|
+
|
|
179
|
+
# Get unstaged diff
|
|
180
|
+
unstaged_diff_result = self._run_git_command(["diff"])
|
|
181
|
+
|
|
182
|
+
# Parse status output into GitFile objects
|
|
183
|
+
files = self._parse_status_output(status_result.stdout)
|
|
184
|
+
|
|
185
|
+
return GitStatus(
|
|
186
|
+
files=files,
|
|
187
|
+
staged_diff=staged_diff_result.stdout,
|
|
188
|
+
unstaged_diff=unstaged_diff_result.stdout,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def _parse_status_output(self, status_output: str) -> List[GitFile]:
|
|
192
|
+
"""Parse git status --porcelain output into GitFile objects."""
|
|
193
|
+
files = []
|
|
194
|
+
for line in status_output.strip().split("\n"):
|
|
195
|
+
if not line:
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
# Git status format: XY filename
|
|
199
|
+
# X = staged status, Y = unstaged status
|
|
200
|
+
if len(line) < 3:
|
|
201
|
+
continue
|
|
202
|
+
|
|
203
|
+
staged_status = line[0]
|
|
204
|
+
unstaged_status = line[1]
|
|
205
|
+
filename = line[3:] # Skip the space
|
|
206
|
+
|
|
207
|
+
files.append(
|
|
208
|
+
GitFile(
|
|
209
|
+
path=filename, status=unstaged_status, staged_status=staged_status
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
return files
|
|
214
|
+
|
|
215
|
+
def stage_files(self, paths: Optional[List[str]] = None) -> None:
|
|
216
|
+
"""
|
|
217
|
+
Stage files for commit.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
paths: List of file paths to stage. If None, stages all files (git add .).
|
|
221
|
+
"""
|
|
222
|
+
if paths is None:
|
|
223
|
+
self._run_git_command(["add", "."])
|
|
224
|
+
else:
|
|
225
|
+
# Stage files in batches to avoid command line length limits
|
|
226
|
+
batch_size = 100
|
|
227
|
+
for i in range(0, len(paths), batch_size):
|
|
228
|
+
batch = paths[i : i + batch_size]
|
|
229
|
+
self._run_git_command(["add"] + batch)
|
|
230
|
+
|
|
231
|
+
def stage_modified(self) -> None:
|
|
232
|
+
"""Stage all modified files (git add -u)."""
|
|
233
|
+
self._run_git_command(["add", "-u"])
|
|
234
|
+
|
|
235
|
+
def unstage_files(self, paths: Optional[List[str]] = None) -> None:
|
|
236
|
+
"""
|
|
237
|
+
Unstage files.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
paths: List of file paths to unstage. If None, unstages all files.
|
|
241
|
+
"""
|
|
242
|
+
if paths is None:
|
|
243
|
+
self._run_git_command(["reset", "HEAD"])
|
|
244
|
+
else:
|
|
245
|
+
self._run_git_command(["reset", "HEAD"] + paths)
|
|
246
|
+
|
|
247
|
+
def commit(self, message: Optional[str] = None, use_editor: bool = False) -> str:
|
|
248
|
+
"""
|
|
249
|
+
Create a commit with the given message or using git's editor.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
message: Commit message. Used as template if use_editor is True.
|
|
253
|
+
use_editor: Whether to use git's configured editor.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Commit SHA.
|
|
257
|
+
|
|
258
|
+
Raises:
|
|
259
|
+
GitCommandError: If commit fails.
|
|
260
|
+
"""
|
|
261
|
+
if use_editor:
|
|
262
|
+
import tempfile
|
|
263
|
+
import os
|
|
264
|
+
|
|
265
|
+
# Create temp file with message as starting point
|
|
266
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
|
|
267
|
+
if message:
|
|
268
|
+
f.write(message)
|
|
269
|
+
temp_file = f.name
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
args = ["commit", "-e", "-F", temp_file]
|
|
273
|
+
|
|
274
|
+
# Run interactively without capturing output
|
|
275
|
+
cmd = ["git"] + args
|
|
276
|
+
subprocess.run(
|
|
277
|
+
cmd,
|
|
278
|
+
cwd=self.repo_path,
|
|
279
|
+
timeout=self.timeout,
|
|
280
|
+
check=True,
|
|
281
|
+
)
|
|
282
|
+
except subprocess.CalledProcessError:
|
|
283
|
+
raise GitCommandError(f"Git commit failed: {' '.join(cmd)}")
|
|
284
|
+
except subprocess.TimeoutExpired:
|
|
285
|
+
raise GitCommandError(f"Git commit timed out: {' '.join(cmd)}")
|
|
286
|
+
finally:
|
|
287
|
+
# Clean up temp file
|
|
288
|
+
os.unlink(temp_file)
|
|
289
|
+
else:
|
|
290
|
+
if message is None:
|
|
291
|
+
raise ValueError("message is required when use_editor is False")
|
|
292
|
+
args = ["commit", "-m", message]
|
|
293
|
+
|
|
294
|
+
self._run_git_command(args)
|
|
295
|
+
|
|
296
|
+
# Extract commit SHA from output
|
|
297
|
+
sha_result = self._run_git_command(["rev-parse", "HEAD"])
|
|
298
|
+
return sha_result.stdout.strip()
|
|
299
|
+
|
|
300
|
+
def get_recent_commits(self, limit: int = 10) -> List[Tuple[str, str]]:
|
|
301
|
+
"""
|
|
302
|
+
Get recent commit history.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
limit: Number of commits to retrieve.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
List of tuples (sha, message).
|
|
309
|
+
"""
|
|
310
|
+
result = self._run_git_command(
|
|
311
|
+
["log", f"--max-count={limit}", "--pretty=format:%H|%s"]
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
commits = []
|
|
315
|
+
for line in result.stdout.strip().split("\n"):
|
|
316
|
+
if "|" in line:
|
|
317
|
+
sha, message = line.split("|", 1)
|
|
318
|
+
commits.append((sha, message))
|
|
319
|
+
|
|
320
|
+
return commits
|
|
321
|
+
|
|
322
|
+
def get_current_branch(self) -> str:
|
|
323
|
+
"""Get the name of the current branch."""
|
|
324
|
+
result = self._run_git_command(["rev-parse", "--abbrev-ref", "HEAD"])
|
|
325
|
+
return result.stdout.strip()
|
|
326
|
+
|
|
327
|
+
def has_changes(self) -> bool:
|
|
328
|
+
"""Check if there are any changes (staged, unstaged, or untracked)."""
|
|
329
|
+
status = self.get_status()
|
|
330
|
+
return (
|
|
331
|
+
status.has_staged_changes
|
|
332
|
+
or status.has_unstaged_changes
|
|
333
|
+
or status.has_untracked_files
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
def get_diff(self, staged: bool = False, paths: Optional[List[str]] = None) -> str:
|
|
337
|
+
"""
|
|
338
|
+
Get diff output.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
staged: Whether to get staged diff (--staged flag).
|
|
342
|
+
paths: Specific paths to diff.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
Diff output as string.
|
|
346
|
+
"""
|
|
347
|
+
args = ["diff"]
|
|
348
|
+
if staged:
|
|
349
|
+
args.append("--staged")
|
|
350
|
+
if paths:
|
|
351
|
+
args.extend(["--"] + paths)
|
|
352
|
+
|
|
353
|
+
result = self._run_git_command(args)
|
|
354
|
+
return result.stdout
|
|
355
|
+
|
|
356
|
+
def get_file_content(self, path: str, revision: str = "HEAD") -> str:
|
|
357
|
+
"""
|
|
358
|
+
Get content of a file at a specific revision.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
path: File path.
|
|
362
|
+
revision: Git revision (default: HEAD).
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
File content as string.
|
|
366
|
+
"""
|
|
367
|
+
result = self._run_git_command(["show", f"{revision}:{path}"])
|
|
368
|
+
return result.stdout
|
|
File without changes
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 2
|
|
3
|
+
requires-python = ">=3.12"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "annotated-types"
|
|
7
|
+
version = "0.7.0"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "certifi"
|
|
16
|
+
version = "2025.7.14"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" }
|
|
19
|
+
wheels = [
|
|
20
|
+
{ url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" },
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "charset-normalizer"
|
|
25
|
+
version = "3.4.2"
|
|
26
|
+
source = { registry = "https://pypi.org/simple" }
|
|
27
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" }
|
|
28
|
+
wheels = [
|
|
29
|
+
{ url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" },
|
|
30
|
+
{ url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" },
|
|
31
|
+
{ url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" },
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" },
|
|
33
|
+
{ url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" },
|
|
34
|
+
{ url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" },
|
|
35
|
+
{ url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" },
|
|
36
|
+
{ url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" },
|
|
37
|
+
{ url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" },
|
|
38
|
+
{ url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" },
|
|
39
|
+
{ url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" },
|
|
40
|
+
{ url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" },
|
|
41
|
+
{ url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" },
|
|
42
|
+
{ url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" },
|
|
43
|
+
{ url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" },
|
|
44
|
+
{ url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" },
|
|
45
|
+
{ url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" },
|
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" },
|
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" },
|
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" },
|
|
49
|
+
{ url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" },
|
|
50
|
+
{ url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" },
|
|
51
|
+
{ url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" },
|
|
52
|
+
{ url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" },
|
|
53
|
+
{ url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" },
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" },
|
|
55
|
+
{ url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[[package]]
|
|
59
|
+
name = "click"
|
|
60
|
+
version = "8.2.1"
|
|
61
|
+
source = { registry = "https://pypi.org/simple" }
|
|
62
|
+
dependencies = [
|
|
63
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
64
|
+
]
|
|
65
|
+
sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" }
|
|
66
|
+
wheels = [
|
|
67
|
+
{ url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" },
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[[package]]
|
|
71
|
+
name = "colorama"
|
|
72
|
+
version = "0.4.6"
|
|
73
|
+
source = { registry = "https://pypi.org/simple" }
|
|
74
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
75
|
+
wheels = [
|
|
76
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[[package]]
|
|
80
|
+
name = "git-copilot-commit"
|
|
81
|
+
version = "0.1.0"
|
|
82
|
+
source = { editable = "." }
|
|
83
|
+
dependencies = [
|
|
84
|
+
{ name = "pycopilot" },
|
|
85
|
+
{ name = "rich" },
|
|
86
|
+
{ name = "typer" },
|
|
87
|
+
{ name = "xdg-base-dirs" },
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[package.metadata]
|
|
91
|
+
requires-dist = [
|
|
92
|
+
{ name = "pycopilot", specifier = ">=0.1.1" },
|
|
93
|
+
{ name = "rich", specifier = ">=14.0.0" },
|
|
94
|
+
{ name = "typer", specifier = ">=0.16.0" },
|
|
95
|
+
{ name = "xdg-base-dirs", specifier = ">=6.0.2" },
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
[[package]]
|
|
99
|
+
name = "idna"
|
|
100
|
+
version = "3.10"
|
|
101
|
+
source = { registry = "https://pypi.org/simple" }
|
|
102
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
|
|
103
|
+
wheels = [
|
|
104
|
+
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
[[package]]
|
|
108
|
+
name = "markdown-it-py"
|
|
109
|
+
version = "3.0.0"
|
|
110
|
+
source = { registry = "https://pypi.org/simple" }
|
|
111
|
+
dependencies = [
|
|
112
|
+
{ name = "mdurl" },
|
|
113
|
+
]
|
|
114
|
+
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
|
|
115
|
+
wheels = [
|
|
116
|
+
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
[[package]]
|
|
120
|
+
name = "mdurl"
|
|
121
|
+
version = "0.1.2"
|
|
122
|
+
source = { registry = "https://pypi.org/simple" }
|
|
123
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
|
124
|
+
wheels = [
|
|
125
|
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
[[package]]
|
|
129
|
+
name = "platformdirs"
|
|
130
|
+
version = "4.3.8"
|
|
131
|
+
source = { registry = "https://pypi.org/simple" }
|
|
132
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" }
|
|
133
|
+
wheels = [
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" },
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
[[package]]
|
|
138
|
+
name = "prompt-toolkit"
|
|
139
|
+
version = "3.0.51"
|
|
140
|
+
source = { registry = "https://pypi.org/simple" }
|
|
141
|
+
dependencies = [
|
|
142
|
+
{ name = "wcwidth" },
|
|
143
|
+
]
|
|
144
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" }
|
|
145
|
+
wheels = [
|
|
146
|
+
{ url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" },
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
[[package]]
|
|
150
|
+
name = "pycopilot"
|
|
151
|
+
version = "0.1.1"
|
|
152
|
+
source = { registry = "https://pypi.org/simple" }
|
|
153
|
+
dependencies = [
|
|
154
|
+
{ name = "platformdirs" },
|
|
155
|
+
{ name = "prompt-toolkit" },
|
|
156
|
+
{ name = "pydantic" },
|
|
157
|
+
{ name = "questionary" },
|
|
158
|
+
{ name = "requests" },
|
|
159
|
+
{ name = "rich" },
|
|
160
|
+
{ name = "typer" },
|
|
161
|
+
]
|
|
162
|
+
sdist = { url = "https://files.pythonhosted.org/packages/56/8e/3f2633fa37a6ab712c7608ab0ca640663e45ebcecf9ec8625d2a10206598/pycopilot-0.1.1.tar.gz", hash = "sha256:9b8322d78d3c3d2546fee62f4deebd130808775862344423357f373fcfc2cd30", size = 33847, upload-time = "2025-07-17T02:19:57.341Z" }
|
|
163
|
+
wheels = [
|
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/c5/92/169a7a85f92c762bd3a58590f6afc36b380f82aa3938946a446bc2f039f2/pycopilot-0.1.1-py3-none-any.whl", hash = "sha256:9d3df1138a380b1d83d6f2bdf32d2aacc2443bbea6bb8f918fe804683dc19d91", size = 10565, upload-time = "2025-07-17T02:19:56.128Z" },
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
[[package]]
|
|
168
|
+
name = "pydantic"
|
|
169
|
+
version = "2.11.7"
|
|
170
|
+
source = { registry = "https://pypi.org/simple" }
|
|
171
|
+
dependencies = [
|
|
172
|
+
{ name = "annotated-types" },
|
|
173
|
+
{ name = "pydantic-core" },
|
|
174
|
+
{ name = "typing-extensions" },
|
|
175
|
+
{ name = "typing-inspection" },
|
|
176
|
+
]
|
|
177
|
+
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
|
|
178
|
+
wheels = [
|
|
179
|
+
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
[[package]]
|
|
183
|
+
name = "pydantic-core"
|
|
184
|
+
version = "2.33.2"
|
|
185
|
+
source = { registry = "https://pypi.org/simple" }
|
|
186
|
+
dependencies = [
|
|
187
|
+
{ name = "typing-extensions" },
|
|
188
|
+
]
|
|
189
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
|
|
190
|
+
wheels = [
|
|
191
|
+
{ url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
|
|
192
|
+
{ url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
|
|
193
|
+
{ url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
|
|
194
|
+
{ url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
|
|
195
|
+
{ url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
|
|
196
|
+
{ url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
|
|
197
|
+
{ url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
|
|
198
|
+
{ url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
|
|
199
|
+
{ url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
|
|
200
|
+
{ url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
|
|
201
|
+
{ url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
|
|
202
|
+
{ url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
|
|
203
|
+
{ url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
|
|
204
|
+
{ url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
|
|
205
|
+
{ url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
|
|
206
|
+
{ url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
|
|
207
|
+
{ url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
|
|
208
|
+
{ url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
|
|
209
|
+
{ url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
|
|
210
|
+
{ url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
|
|
211
|
+
{ url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
|
|
212
|
+
{ url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
|
|
213
|
+
{ url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
|
|
214
|
+
{ url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
|
|
215
|
+
{ url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
|
|
216
|
+
{ url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
|
|
217
|
+
{ url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
|
|
218
|
+
{ url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
|
|
219
|
+
{ url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
|
|
220
|
+
{ url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
|
|
221
|
+
{ url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
[[package]]
|
|
225
|
+
name = "pygments"
|
|
226
|
+
version = "2.19.2"
|
|
227
|
+
source = { registry = "https://pypi.org/simple" }
|
|
228
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
229
|
+
wheels = [
|
|
230
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
[[package]]
|
|
234
|
+
name = "questionary"
|
|
235
|
+
version = "2.1.0"
|
|
236
|
+
source = { registry = "https://pypi.org/simple" }
|
|
237
|
+
dependencies = [
|
|
238
|
+
{ name = "prompt-toolkit" },
|
|
239
|
+
]
|
|
240
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/b8/d16eb579277f3de9e56e5ad25280fab52fc5774117fb70362e8c2e016559/questionary-2.1.0.tar.gz", hash = "sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587", size = 26775, upload-time = "2024-12-29T11:49:17.802Z" }
|
|
241
|
+
wheels = [
|
|
242
|
+
{ url = "https://files.pythonhosted.org/packages/ad/3f/11dd4cd4f39e05128bfd20138faea57bec56f9ffba6185d276e3107ba5b2/questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec", size = 36747, upload-time = "2024-12-29T11:49:16.734Z" },
|
|
243
|
+
]
|
|
244
|
+
|
|
245
|
+
[[package]]
|
|
246
|
+
name = "requests"
|
|
247
|
+
version = "2.32.4"
|
|
248
|
+
source = { registry = "https://pypi.org/simple" }
|
|
249
|
+
dependencies = [
|
|
250
|
+
{ name = "certifi" },
|
|
251
|
+
{ name = "charset-normalizer" },
|
|
252
|
+
{ name = "idna" },
|
|
253
|
+
{ name = "urllib3" },
|
|
254
|
+
]
|
|
255
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" }
|
|
256
|
+
wheels = [
|
|
257
|
+
{ url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" },
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
[[package]]
|
|
261
|
+
name = "rich"
|
|
262
|
+
version = "14.0.0"
|
|
263
|
+
source = { registry = "https://pypi.org/simple" }
|
|
264
|
+
dependencies = [
|
|
265
|
+
{ name = "markdown-it-py" },
|
|
266
|
+
{ name = "pygments" },
|
|
267
|
+
]
|
|
268
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
|
|
269
|
+
wheels = [
|
|
270
|
+
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
[[package]]
|
|
274
|
+
name = "shellingham"
|
|
275
|
+
version = "1.5.4"
|
|
276
|
+
source = { registry = "https://pypi.org/simple" }
|
|
277
|
+
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
|
278
|
+
wheels = [
|
|
279
|
+
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
|
280
|
+
]
|
|
281
|
+
|
|
282
|
+
[[package]]
|
|
283
|
+
name = "typer"
|
|
284
|
+
version = "0.16.0"
|
|
285
|
+
source = { registry = "https://pypi.org/simple" }
|
|
286
|
+
dependencies = [
|
|
287
|
+
{ name = "click" },
|
|
288
|
+
{ name = "rich" },
|
|
289
|
+
{ name = "shellingham" },
|
|
290
|
+
{ name = "typing-extensions" },
|
|
291
|
+
]
|
|
292
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" }
|
|
293
|
+
wheels = [
|
|
294
|
+
{ url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" },
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
[[package]]
|
|
298
|
+
name = "typing-extensions"
|
|
299
|
+
version = "4.14.1"
|
|
300
|
+
source = { registry = "https://pypi.org/simple" }
|
|
301
|
+
sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" }
|
|
302
|
+
wheels = [
|
|
303
|
+
{ url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" },
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
[[package]]
|
|
307
|
+
name = "typing-inspection"
|
|
308
|
+
version = "0.4.1"
|
|
309
|
+
source = { registry = "https://pypi.org/simple" }
|
|
310
|
+
dependencies = [
|
|
311
|
+
{ name = "typing-extensions" },
|
|
312
|
+
]
|
|
313
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
|
|
314
|
+
wheels = [
|
|
315
|
+
{ url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
[[package]]
|
|
319
|
+
name = "urllib3"
|
|
320
|
+
version = "2.5.0"
|
|
321
|
+
source = { registry = "https://pypi.org/simple" }
|
|
322
|
+
sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
|
|
323
|
+
wheels = [
|
|
324
|
+
{ url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
[[package]]
|
|
328
|
+
name = "wcwidth"
|
|
329
|
+
version = "0.2.13"
|
|
330
|
+
source = { registry = "https://pypi.org/simple" }
|
|
331
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" }
|
|
332
|
+
wheels = [
|
|
333
|
+
{ url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" },
|
|
334
|
+
]
|
|
335
|
+
|
|
336
|
+
[[package]]
|
|
337
|
+
name = "xdg-base-dirs"
|
|
338
|
+
version = "6.0.2"
|
|
339
|
+
source = { registry = "https://pypi.org/simple" }
|
|
340
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bf/d0/bbe05a15347538aaf9fa5b51ac3b97075dfb834931fcb77d81fbdb69e8f6/xdg_base_dirs-6.0.2.tar.gz", hash = "sha256:950504e14d27cf3c9cb37744680a43bf0ac42efefc4ef4acf98dc736cab2bced", size = 4085, upload-time = "2024-10-19T14:35:08.114Z" }
|
|
341
|
+
wheels = [
|
|
342
|
+
{ url = "https://files.pythonhosted.org/packages/fc/03/030b47fd46b60fc87af548e57ff59c2ca84b2a1dadbe721bb0ce33896b2e/xdg_base_dirs-6.0.2-py3-none-any.whl", hash = "sha256:3c01d1b758ed4ace150ac960ac0bd13ce4542b9e2cdf01312dcda5012cfebabe", size = 4747, upload-time = "2024-10-19T14:35:05.931Z" },
|
|
343
|
+
]
|