gitpr-cli 0.0.23__py3-none-any.whl → 0.0.25__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpr-cli
3
- Version: 0.0.23
3
+ Version: 0.0.25
4
4
  Summary: Automação de PRs, Commits e Code Review com IA (Gemini e DeepSeek)
5
5
  Author-email: Natan Fiuza <contato@natanfiuza.dev.br>
6
6
  Requires-Python: >=3.10
@@ -0,0 +1,23 @@
1
+ gitpr_cli-0.0.25.dist-info/licenses/LICENSE,sha256=UQzLC6mwqb-ZNDkBBAqOxC-SMQcEID0gaM6oFcu6u48,27030
2
+ src/__init__.py,sha256=U6ksarernNcryHO20aj4rNG7w0thT7xdMs5KzBJyPvE,28
3
+ src/ai_providers.py,sha256=rf4IJTG6P8nLKU-C-BdUdy68JvhnsgzvhEsJdp-9El0,3477
4
+ src/blame_engine.py,sha256=Ci7t08xTcC1kBWAjQ_ulP-Zraau_PC35MDfAngc4AYk,10396
5
+ src/cache.py,sha256=XggMTy00GlZfeF1VoLEYCdxL5h0eTg11TJfPIRPx7fs,3201
6
+ src/config.py,sha256=VJ9ekDlTVG5ETWDuO1kZWlgrncXbrvduxa5Zg7wN_ZY,9064
7
+ src/core.py,sha256=MtcbftxhFFADNKzf6YBImeeTwW3oFxkQgvUArv-aHLA,18246
8
+ src/i18n.py,sha256=Bn1OrhCYEaT0kUidu5SeTu6kiIuWOZ4OjB-7mIb6RtY,3185
9
+ src/issue_engine.py,sha256=435kPPgdsFMcY3nvutxdIfJAnLP0U4FMCPdbok6C2sc,3626
10
+ src/linter_engine.py,sha256=D04wvOgRa-vZEYknm-z-Cg7V_3gnoQz_64PMorWnISo,4414
11
+ src/main.py,sha256=k4WNlrqWHZqR1t7-IGfKUpmlxjTyp17dulP_cS01jho,27734
12
+ src/security.py,sha256=Li0zM8ZURTK2nKRHIt49TWLO4DIddBEHzXPrVycv0Rs,1343
13
+ src/spinner.py,sha256=LeawExgx7lnHUvyuIlEx0Bc4WlAfC5KzSRWMEiu-ufY,6331
14
+ src/tui_issue.py,sha256=gcAJCIfMcdeMjrFJUWQQvdgBv7fnOBtxQxwdBk2Sk40,1789
15
+ src/updater.py,sha256=JEzyGu6pcdrKDziCSU8iM-yjStC-3ii6o76GUHfj3Zw,5886
16
+ src/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ src/ui/help_screen.py,sha256=tjbokXhwyzLnkOC0S56NbpX-78hcFQnvsQMpNU1wt0c,1862
18
+ src/ui/issue_app.py,sha256=8MdBcOVdCHPFx6EUhs80CiZ2G-29KulskkCz9qMZ_Lg,4737
19
+ gitpr_cli-0.0.25.dist-info/METADATA,sha256=EcoI5mi-eX_wE8qpmmN1AuVC6RGDDVzparNEIUPyVwQ,15488
20
+ gitpr_cli-0.0.25.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
21
+ gitpr_cli-0.0.25.dist-info/entry_points.txt,sha256=mh_4F_idM4cj0XhfRGBDQb5Nnku93YJ-dyKh5SufwlE,39
22
+ gitpr_cli-0.0.25.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
23
+ gitpr_cli-0.0.25.dist-info/RECORD,,
src/ai_providers.py CHANGED
@@ -34,11 +34,13 @@ def call_ai_model(provider, api_key, api_model, prompt, system_instruction, quie
34
34
  )
35
35
  result_text = response.text
36
36
 
37
- elif provider == "deepseek":
38
- # DeepSeek is 100% compatible with the OpenAI library
39
- client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
37
+ elif provider in ["deepseek", "ollama"]:
38
+ # DeepSeek and Ollama are 100% compatible with the OpenAI library.
39
+ base_url = "https://api.deepseek.com" if provider == "deepseek" else "http://localhost:11434/v1"
40
+ client = OpenAI(api_key=api_key, base_url=base_url)
41
+
40
42
  response = client.chat.completions.create(
41
- model=api_model, # e.g.: "deepseek-chat"
43
+ model=api_model,
42
44
  messages=[
43
45
  {"role": "system", "content": system_instruction},
44
46
  {"role": "user", "content": prompt}
src/blame_engine.py CHANGED
@@ -4,7 +4,7 @@ import re
4
4
  import os
5
5
  from datetime import datetime
6
6
  from src.core import get_current_branch
7
- from src.config import get_api_key, get_api_model, get_ai_provider
7
+ from src.config import get_api_key, get_api_model, get_ai_provider, resolve_skill_path
8
8
  from src.ai_providers import call_ai_model
9
9
  from src.i18n import __
10
10
 
@@ -69,7 +69,7 @@ def analyze_commit_with_ai(commit_hash, file_path):
69
69
  # Use the 'simple' model (Flash/Lite) to save money in the loop
70
70
  api_model = get_api_model(provider, task_complexity="simple")
71
71
 
72
- skill_path = os.path.join(os.getcwd(), ".gitpr.blame.md")
72
+ skill_path = resolve_skill_path(".gitpr.blame.md")
73
73
  if os.path.exists(skill_path):
74
74
  with open(skill_path, "r", encoding="utf-8") as f:
75
75
  sys_inst = f.read()
src/config.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import sys
3
3
  import socket
4
+ import shutil
4
5
  import click
5
6
  import yaml
6
7
  from pathlib import Path
@@ -18,6 +19,8 @@ DEFAULT_CONFIG = {
18
19
  "GEMINI_API_MODEL_SECONDARY": "gemini-flash-lite-latest",
19
20
  "DEEPSEEK_API_MODEL_PRIMARY": "deepseek-v4-pro",
20
21
  "DEEPSEEK_API_MODEL_SECONDARY": "deepseek-v4-flash",
22
+ "OLLAMA_API_MODEL_PRIMARY": "llama3",
23
+ "OLLAMA_API_MODEL_SECONDARY": "llama3",
21
24
  "OUTPUT_FILE_NAME": "{branch}_{datetime}_PR_DESC.md",
22
25
  "OUTPUT_FILE_NAME_REVIEW": "{branch}_{datetime}_PR_REVIEW.txt",
23
26
  "OUTPUT_FILE_NAME_FULLREVIEW": "{branch}_{datetime}_PR_FULLREVIEW.txt",
@@ -26,6 +29,41 @@ DEFAULT_CONFIG = {
26
29
  "OUTPUT_FILE_NAME_ISSUE": "{branch}_{datetime}_ISSUE.md"
27
30
  }
28
31
 
32
+ def get_skill_dir():
33
+ """Returns the absolute path to the project's skill folder (.gitpr/skill)."""
34
+ return os.path.join(os.getcwd(), ".gitpr", "skill")
35
+
36
+
37
+ def resolve_skill_path(filename):
38
+ """
39
+ Resolves the path of a skill/config file (e.g.: .gitpr.commit.md).
40
+
41
+ The canonical location is the '.gitpr/skill/' folder inside the project.
42
+ For backward compatibility, if the file still lives in the project root,
43
+ it is transparently migrated (moved) into '.gitpr/skill/'.
44
+
45
+ Always returns the path inside '.gitpr/skill/' (whether the file exists or
46
+ not), unless a migration failed — in that case it falls back to the legacy
47
+ root path so the tool keeps working.
48
+ """
49
+ skill_dir = get_skill_dir()
50
+ target_path = os.path.join(skill_dir, filename)
51
+ legacy_path = os.path.join(os.getcwd(), filename)
52
+
53
+ # Migrate a legacy root file into the skill folder (only if not already there)
54
+ if os.path.exists(legacy_path) and not os.path.exists(target_path):
55
+ try:
56
+ os.makedirs(skill_dir, exist_ok=True)
57
+ shutil.move(legacy_path, target_path)
58
+ click.secho(__("📦 Skill file {filename} moved to .gitpr/skill/", filename=filename), fg="cyan", dim=True)
59
+ except Exception as e:
60
+ # If moving fails, fall back to the legacy location so the tool keeps working
61
+ click.secho(__("⚠️ Warning: Could not move {filename} to .gitpr/skill/ ({error})", filename=filename, error=str(e)), fg="yellow")
62
+ return legacy_path
63
+
64
+ return target_path
65
+
66
+
29
67
  def get_ai_provider():
30
68
  """Returns the configured default AI provider, or 'gemini' as fallback."""
31
69
  load_dotenv(ENV_FILE)
@@ -35,10 +73,17 @@ def get_api_key(provider):
35
73
  """Reads and decrypts the API key corresponding to the chosen provider."""
36
74
  load_dotenv(ENV_FILE)
37
75
 
76
+ # Suporte a CI/CD: Tenta ler a chave raw primeiro (ex: injetada via GitHub Secrets)
77
+ raw_key = os.getenv(f"{provider.upper()}_API_KEY")
78
+ if raw_key:
79
+ return raw_key
80
+
38
81
  if provider == "gemini":
39
82
  encrypted_key = os.getenv("GEMINI_API_KEY_ENCRYPTED")
40
83
  elif provider == "deepseek":
41
84
  encrypted_key = os.getenv("DEEPSEEK_API_KEY_ENCRYPTED")
85
+ elif provider == "ollama":
86
+ return "ollama-local" # Olama does not require authentication!
42
87
  else:
43
88
  return None
44
89
 
@@ -86,7 +131,7 @@ def setup_environment():
86
131
  click.secho(__("🤖 Welcome to GitPR! Let's configure your AI engine."), fg="cyan", bold=True)
87
132
  provider = click.prompt(
88
133
  __("Which artificial intelligence do you want to use as default?"),
89
- type=click.Choice(['gemini', 'deepseek'], case_sensitive=False),
134
+ type=click.Choice(['gemini', 'deepseek', 'ollama'], case_sensitive=False),
90
135
  default='gemini'
91
136
  ).lower()
92
137
  set_key(ENV_FILE, "DEFAULT_AI_PROVIDER", provider)
@@ -95,6 +140,12 @@ def setup_environment():
95
140
  # Check if the chosen provider's key exists
96
141
  api_key = get_api_key(provider)
97
142
  if not api_key:
143
+ # 🛡️ Escudo de CI/CD: Impede que o prompt trave a pipeline do GitHub Actions
144
+ if os.getenv("CI") or os.getenv("GITHUB_ACTIONS"):
145
+ click.secho(__("❌ Error: API Key not configured for provider '{provider}' in the CI/CD environment.", provider=provider), fg="red")
146
+ click.secho(__("💡 Tip: Pass the key as an environment variable (e.g., GEMINI_API_KEY)."), fg="yellow")
147
+ sys.exit(1)
148
+
98
149
  click.secho(__("🔑 API Key for {provider} not found.", provider=provider.capitalize()), fg="yellow")
99
150
  raw_key = click.prompt(__("Paste your {provider} API key here", provider=provider.capitalize()), hide_input=True)
100
151
 
@@ -132,7 +183,7 @@ def load_linter_rules():
132
183
  Loads the static linter rules from the .gitpr.linter.yml file.
133
184
  Returns a list of rules or an empty list if the file does not exist.
134
185
  """
135
- file_path = os.path.join(os.getcwd(), ".gitpr.linter.yml")
186
+ file_path = resolve_skill_path(".gitpr.linter.yml")
136
187
 
137
188
  # If the file does not exist in the project, it's not an error. There are simply no rules to apply.
138
189
  if not os.path.exists(file_path):
src/core.py CHANGED
@@ -9,7 +9,7 @@ import urllib.error
9
9
  from google import genai
10
10
  from src.security import decrypt_data
11
11
  from src.cache import get_cached_response, save_cached_response, get_cached_pr_descriptions
12
- from src.config import get_api_key, get_api_model
12
+ from src.config import get_api_key, get_api_model, get_skill_dir, resolve_skill_path
13
13
  from src.ai_providers import call_ai_model
14
14
  from src.i18n import __, CURRENT_LANG
15
15
 
@@ -130,10 +130,10 @@ def get_skill_context(action_type="pr"):
130
130
  else: # review or fullreview
131
131
  target_file = ".gitpr.review.md"
132
132
 
133
- skill_file = os.path.join(os.getcwd(), target_file)
133
+ skill_file = resolve_skill_path(target_file)
134
134
 
135
135
  # Fallback to the old file (for backward compatibility with previous version users)
136
- legacy_file = os.path.join(os.getcwd(), ".gitpr.md")
136
+ legacy_file = resolve_skill_path(".gitpr.md")
137
137
 
138
138
  # Check the new one first; if not found, try the old one
139
139
  file_to_load = skill_file if os.path.exists(skill_file) else (legacy_file if os.path.exists(legacy_file) else None)
@@ -252,11 +252,16 @@ def generate_skill_template():
252
252
  }
253
253
 
254
254
  success_count = 0
255
-
255
+
256
+ # Templates now live inside the project's .gitpr/skill/ folder
257
+ skill_dir = get_skill_dir()
258
+ os.makedirs(skill_dir, exist_ok=True)
259
+
256
260
  for local_name, remote_name in files_to_download.items():
257
- file_path = os.path.join(os.getcwd(), local_name)
261
+ # Migrate any legacy root file into .gitpr/skill/ and resolve final path
262
+ file_path = resolve_skill_path(local_name)
258
263
  url = base_url + remote_name
259
-
264
+
260
265
  if os.path.exists(file_path):
261
266
  click.secho(__("⚠️ File {local_name} already exists in this directory. It will not be overwritten.", local_name=local_name), fg="yellow")
262
267
  continue
@@ -278,9 +283,9 @@ def generate_skill_template():
278
283
 
279
284
  if success_count > 0:
280
285
  click.secho(__("\n✅ Base templates successfully configured!"), fg="green", bold=True)
281
- click.echo(__("You can now open the generated files and customize the tool's behavior for your project:\n"))
282
- click.echo(__(" 1. Architecture rules for AI in '.gitpr.pr.md' and '.gitpr.review.md'\n"))
283
- click.echo(__(" 2. Local regex rules in '.gitpr.linter.yml'\n"))
286
+ click.echo(__("You can now open the generated files in '.gitpr/skill/' and customize the tool's behavior for your project:\n"))
287
+ click.echo(__(" 1. Architecture rules for AI in '.gitpr/skill/.gitpr.pr.md' and '.gitpr/skill/.gitpr.review.md'\n"))
288
+ click.echo(__(" 2. Local regex rules in '.gitpr/skill/.gitpr.linter.yml'\n"))
284
289
  else:
285
290
  click.echo(__("\nNo new files were downloaded."))
286
291
 
src/issue_engine.py CHANGED
@@ -4,7 +4,7 @@ import os
4
4
  import click
5
5
  from src.ai_providers import call_ai_model
6
6
  from src.cache import get_cached_response, save_cached_response
7
- from src.config import get_api_key, get_api_model, get_ai_provider
7
+ from src.config import get_api_key, get_api_model, get_ai_provider, resolve_skill_path
8
8
  from src.ai_providers import call_ai_model
9
9
  from src.i18n import __
10
10
 
@@ -45,7 +45,7 @@ def generate_issue_content(context_text, context_type="diff"):
45
45
  # Use the advanced model to ensure Issue structure quality
46
46
  api_model = get_api_model(provider, task_complexity="advanced")
47
47
 
48
- skill_path = os.path.join(os.getcwd(), ".gitpr.issue.md")
48
+ skill_path = resolve_skill_path(".gitpr.issue.md")
49
49
  sys_inst = ""
50
50
 
51
51
  if os.path.exists(skill_path):
src/main.py CHANGED
@@ -66,7 +66,7 @@ HELP_MAP: dict[str, dict[str, str]] = {
66
66
  'skill': {
67
67
  'url': get_doc_url('skill-template.md'),
68
68
  'title': __('Skills and Templates System (--skill)'),
69
- 'description': __('Downloads template files (.gitpr.*.md and .gitpr.linter.yml) from the official repository to the project root. These files allow customizing the AI behavior according to your team\'s rules. NEVER overwrites existing local files.'),
69
+ 'description': __('Downloads template files (.gitpr.*.md and .gitpr.linter.yml) from the official repository into the project\'s .gitpr/skill/ folder. These files allow customizing the AI behavior according to your team\'s rules. NEVER overwrites existing local files.'),
70
70
  },
71
71
  'update': {
72
72
  'url': get_doc_url('auto-update.md'),
@@ -96,7 +96,7 @@ HELP_MAP: dict[str, dict[str, str]] = {
96
96
  'provider': {
97
97
  'url': get_doc_url('providers-ia.md'),
98
98
  'title': __('AI Provider Selection (--provider)'),
99
- 'description': __('Forces the use of a specific AI provider for this execution: gemini (Google Gemini) or deepseek (DeepSeek). Temporarily overrides the default provider defined in the .env file.'),
99
+ 'description': __('Forces the use of a specific AI provider for this execution: gemini (Google Gemini), deepseek (DeepSeek) or ollama (Local). Temporarily overrides the default provider defined in the .env file.'),
100
100
  },
101
101
  }
102
102
 
@@ -124,7 +124,7 @@ HELP_PRIORITY: dict[str, int] = {
124
124
  @click.option('-r', '--review', is_flag=True, help=__("Performs a code review of local changes (git diff)."))
125
125
  @click.option('-f', '--fullreview', is_flag=True, help=__("Performs a code review of all changes since the remote main branch (origin/main)."))
126
126
  @click.option('-l', '--linter', is_flag=True, help=__("Runs only the local static linter (ideal for CI/CD)."))
127
- @click.option('-s', '--skill', is_flag=True, help=__("Generates the .gitpr.md template file in the current folder."))
127
+ @click.option('-s', '--skill', is_flag=True, help=__("Downloads the skill template files into the .gitpr/skill/ folder."))
128
128
  @click.option('-u', '--update', is_flag=True, help=__("Checks and installs the latest version of GitPR."))
129
129
  @click.option('-ih', '--installhooks', is_flag=True, help=__("Automatically installs validation Git Hooks in the project."))
130
130
  @click.option('--hook', type=click.Path(), hidden=True, help=__("Commit file path (internal hook use)."))
@@ -133,7 +133,7 @@ HELP_PRIORITY: dict[str, int] = {
133
133
  @click.option('-b', '--blame', type=str, help=__("Analyzes the origin of a business rule (e.g., file.py:10-20 or just file.py)."))
134
134
  @click.option('-ht', '--history', is_flag=True, help=__("Uses the entire branch history (Git Log + PR Cache) as context to generate the issue."))
135
135
  @click.option('-is', '--issue', is_flag=True, help=__("Generates a standardized Issue from current changes and opens the interactive interface."))
136
- @click.option('-p', '--provider', type=click.Choice(['gemini', 'deepseek']), help=__("Forces the use of a specific AI provider for this execution."))
136
+ @click.option('-p', '--provider', type=click.Choice(['gemini', 'deepseek', 'ollama']), help=__("Forces the use of a specific AI provider for this execution."))
137
137
  @click.option('-h', '--help', 'help_flag', is_flag=True, help=__("Shows this message and exits. Use with another flag for contextual help (e.g., -h --issue)."))
138
138
  def cli(commit, review, fullreview, linter, skill, update, installhooks, hook, quiet, provider, input, blame, history, issue, help_flag):
139
139
  """
src/spinner.py CHANGED
@@ -12,7 +12,7 @@ import threading
12
12
  import urllib.request
13
13
  from pathlib import Path
14
14
  from dotenv import load_dotenv, set_key
15
- from src.i18n import __
15
+ from src.i18n import __, CURRENT_LANG
16
16
 
17
17
  # ANSI color codes
18
18
  MAGENTA = '\033[35m'
@@ -35,10 +35,13 @@ WORD_COLORS = [
35
35
  # Caracteres braille unicode que simulam um giro
36
36
  BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
37
37
 
38
- # URL do template remoto com a lista de palavras
38
+ # URL do template remoto com a lista de palavras (language-aware).
39
+ # English (en) = original file without suffix; other languages get a suffix
40
+ # (e.g.: gitpr.thinking-words.pt_br.md), mirroring generate_skill_template().
41
+ _LANG_SUFFIX = "" if CURRENT_LANG.startswith("en") else f".{CURRENT_LANG}"
39
42
  THINKING_WORDS_URL = (
40
43
  "https://raw.githubusercontent.com/natanfiuza/gitpr/"
41
- "refs/heads/main/templates/gitpr.thinking-words.md"
44
+ f"refs/heads/main/templates/gitpr.thinking-words{_LANG_SUFFIX}.md"
42
45
  )
43
46
 
44
47
  # Fallback interno caso o download falhe
src/updater.py CHANGED
@@ -7,8 +7,8 @@ import click
7
7
  from datetime import datetime
8
8
 
9
9
  # Current version of your local executable (Update this on every new build!)
10
- __version__ = "0.0.22" # GitPR current version
11
- __lang_version__ = "v0.0.1" # Language dictionary version control
10
+ __version__ = "0.0.25" # GitPR current version
11
+ __lang_version__ = "v0.0.3" # Language dictionary version control
12
12
  GITHUB_API_URL = "https://api.github.com/repos/natanfiuza/gitpr/releases/latest"
13
13
  PYPI_API_URL = "https://pypi.org/pypi/gitpr-cli/json"
14
14
 
@@ -1,23 +0,0 @@
1
- gitpr_cli-0.0.23.dist-info/licenses/LICENSE,sha256=UQzLC6mwqb-ZNDkBBAqOxC-SMQcEID0gaM6oFcu6u48,27030
2
- src/__init__.py,sha256=U6ksarernNcryHO20aj4rNG7w0thT7xdMs5KzBJyPvE,28
3
- src/ai_providers.py,sha256=3O91HmlnqE1o5SV0seley_gGH0-3BImVIluHIMpq9lU,3354
4
- src/blame_engine.py,sha256=056Rp5JkQU2cFB4b3lmIx99xjwfLj-tc7jwyevDoik8,10383
5
- src/cache.py,sha256=XggMTy00GlZfeF1VoLEYCdxL5h0eTg11TJfPIRPx7fs,3201
6
- src/config.py,sha256=QpKKpoP0RHpSl2s1zJDfx6wETKqJ8wLtn6T1zAnznis,6621
7
- src/core.py,sha256=eIpnTttGQhUwrEm7Xh59HYVu59LQcprf7K-IwN7kNYk,17965
8
- src/i18n.py,sha256=Bn1OrhCYEaT0kUidu5SeTu6kiIuWOZ4OjB-7mIb6RtY,3185
9
- src/issue_engine.py,sha256=QLEEHp9l6_QiaaLLrFtBU_-LkkxPE2Gs5-TLEYEBWCA,3613
10
- src/linter_engine.py,sha256=D04wvOgRa-vZEYknm-z-Cg7V_3gnoQz_64PMorWnISo,4414
11
- src/main.py,sha256=mzSYqNF7YgdI6vsuwWSgqUks_tA7Zn5gMk6fkebZFIY,27682
12
- src/security.py,sha256=Li0zM8ZURTK2nKRHIt49TWLO4DIddBEHzXPrVycv0Rs,1343
13
- src/spinner.py,sha256=UM-53CfrfQ6Ymg4-d2_pYgMaDdiEV69DFetaQtCyJzo,6055
14
- src/tui_issue.py,sha256=gcAJCIfMcdeMjrFJUWQQvdgBv7fnOBtxQxwdBk2Sk40,1789
15
- src/updater.py,sha256=giLCq9ygRXGhLbVqwLEDZrO2szEIk5nFUMl9NhiZZ90,5886
16
- src/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- src/ui/help_screen.py,sha256=tjbokXhwyzLnkOC0S56NbpX-78hcFQnvsQMpNU1wt0c,1862
18
- src/ui/issue_app.py,sha256=8MdBcOVdCHPFx6EUhs80CiZ2G-29KulskkCz9qMZ_Lg,4737
19
- gitpr_cli-0.0.23.dist-info/METADATA,sha256=2rnIIo3C6OqfV1EZHF5YQNIp1u9FS4U8BJI5TM9FMVM,15488
20
- gitpr_cli-0.0.23.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
21
- gitpr_cli-0.0.23.dist-info/entry_points.txt,sha256=mh_4F_idM4cj0XhfRGBDQb5Nnku93YJ-dyKh5SufwlE,39
22
- gitpr_cli-0.0.23.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
23
- gitpr_cli-0.0.23.dist-info/RECORD,,