airev 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airev
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: CLI tool for AI-powered code review with context backtracking
5
5
  Author-email: Tarcisio <tarcisiojunior@gmail.com>
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
- code_reviewer/__init__.py,sha256=ZT3XI1jn28k1LV34Ujrq42DbzZqkrEo53dPN8gz7lmw,82
2
- code_reviewer/cli.py,sha256=DvVF0o9-hrdUt4D0eWskznDO_Du_1A7LR7GeP8Osujw,6734
1
+ code_reviewer/__init__.py,sha256=39ZhaBH3qjYCSKVmeSRsf21d_-DPx9UOMUCaCnqVRCw,82
2
+ code_reviewer/cli.py,sha256=WaWoN5FFPhOtKoM1LTawCvdT6jb1eVEJyS_G69mYICA,6686
3
3
  code_reviewer/context_builder.py,sha256=XJGsJpc5YOP3jhldpMFnrJ-hLc4uf9O6_efxZa3sbsc,8790
4
4
  code_reviewer/diff_parser.py,sha256=07EO0kJFYuS6GRgDUHH0czYJBKcL8CxLR-jLdq6PShs,6896
5
5
  code_reviewer/models.py,sha256=SUSudQx623zS15yUKd84qOI6zqO-736lu7gjbHSsYwY,4263
@@ -9,18 +9,20 @@ code_reviewer/formatters/__init__.py,sha256=LXkD8nK7yWGtbc6ox85SHWZdQX5sVr5xLXkk
9
9
  code_reviewer/formatters/progress.py,sha256=mUmoB2xQYYuYz5IRJzn23wgOpiV7bXehXrPhP5rDT-g,8529
10
10
  code_reviewer/formatters/terminal.py,sha256=lJohIyqav3QjGchjTUKxfCbuFtbtL3sbcW9glU3hwUM,5849
11
11
  code_reviewer/i18n/__init__.py,sha256=Uzm_sic0_ehZQSpyzxI9-IFX_5Saxo5V-sLR35eqrIM,4696
12
+ code_reviewer/locales/en.yaml,sha256=CiVUrxIj9jnAhZjEw74pInWYljT-o2Luvo1mf1yOo14,1879
13
+ code_reviewer/locales/pt-br.yaml,sha256=iWtokdIjBEikUthPYh8oSYUuvgYA_02rcfgzFcB7tLI,2037
12
14
  code_reviewer/prompts/review_system.md,sha256=9FDaIY8q2PdLh3p28cy2EJBi8olQhtw6I3TYgVG7fik,1995
13
15
  code_reviewer/runners/__init__.py,sha256=cLxawmzHwhymN2xSC7nUWEOpHHvvSklzZOqjy2Q7HIM,1194
14
16
  code_reviewer/runners/base.py,sha256=xikp7yI4IcOX86uNA7CUWTCL_oNuHSF9WIs6OP6rnx0,1491
15
17
  code_reviewer/runners/copilot.py,sha256=GpBYO-Splmo66EaUBfCmU8Et-NRB0w2gn7XEtIq9THw,2433
16
18
  code_reviewer/runners/gemini.py,sha256=dadONQIEb0d_y8V3KgYX65JH8IMYmNAP2jC22r0cWXY,2142
17
- code_reviewer/updater/__init__.py,sha256=VLmFh-6RU5XgdiC5MuUdprGMs1KqTKmSSgiC75ctx5w,342
18
- code_reviewer/updater/http_client.py,sha256=B0ZyZdn2kWeKteWn8P-BWT-uYBWtmeD0p-scbz1bAd0,1754
19
+ code_reviewer/updater/__init__.py,sha256=L4irTnOGif85M55jerbjczIr2SxXj74i_vfvWzvfPQo,374
20
+ code_reviewer/updater/http_client.py,sha256=g4PnuY5KKbsA0EqLtHhOK4sxg_6P0drzd1HKxWKJxZw,1746
19
21
  code_reviewer/updater/notifier.py,sha256=o4crwJOnCOSnzqk5gMt0MkYP3xm-yEXIGSnix988YzA,992
20
- code_reviewer/updater/upgrade.py,sha256=NHMLw0p71qUhXGSxoyeKi3eNT1-DGi3eKEiYMqBZJkw,2404
21
- code_reviewer/updater/version_check.py,sha256=j9B8sM6NZwZe01CuRzQjBgqXIZAkShaht0EBOhuMxOo,4432
22
- airev-1.1.0.dist-info/METADATA,sha256=uc-scP2rjRL2sfXH_JJkFClOccF36aKI9t54bjl2DS0,6258
23
- airev-1.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
24
- airev-1.1.0.dist-info/entry_points.txt,sha256=LDd8UajxUO4QUs63xt6z635doU7E1XzBPFQZeMrlShU,49
25
- airev-1.1.0.dist-info/top_level.txt,sha256=VqPHk5LmBEOeRJOUhXq1lkW5UiT48zW7a9h7NDy9N0E,14
26
- airev-1.1.0.dist-info/RECORD,,
22
+ code_reviewer/updater/upgrade.py,sha256=xoAfpomMJA_K9t6myeXC6tLEBnKwAgxR9OD8tcJ4YXE,5842
23
+ code_reviewer/updater/version_check.py,sha256=2Zv35s5oeR0dHAGODPwO70dyshECaCzrQx7vEZAXYJM,4917
24
+ airev-1.2.0.dist-info/METADATA,sha256=IVqJfD0FVZFSrjWLHgbSywdE4mdR4a0UHQpynHGr5B8,6258
25
+ airev-1.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
26
+ airev-1.2.0.dist-info/entry_points.txt,sha256=LDd8UajxUO4QUs63xt6z635doU7E1XzBPFQZeMrlShU,49
27
+ airev-1.2.0.dist-info/top_level.txt,sha256=VqPHk5LmBEOeRJOUhXq1lkW5UiT48zW7a9h7NDy9N0E,14
28
+ airev-1.2.0.dist-info/RECORD,,
code_reviewer/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Code Reviewer - CLI para revisão de código com IA."""
2
2
 
3
- __version__ = "1.1.0"
3
+ __version__ = "1.2.0"
code_reviewer/cli.py CHANGED
@@ -1,4 +1,4 @@
1
- """CLI Entry Point - Comando principal do code-reviewer."""
1
+ """CLI Entry Point - Comando principal do airev."""
2
2
 
3
3
  import sys
4
4
  import time
@@ -88,13 +88,13 @@ def review(
88
88
 
89
89
  Exemplos:
90
90
 
91
- code-reviewer review --base main
91
+ airev review --base main
92
92
 
93
- code-reviewer review --base develop --runner copilot
93
+ airev review --base develop --runner copilot
94
94
 
95
- code-reviewer review --base main --json-output
95
+ airev review --base main --json-output
96
96
 
97
- code-reviewer review --base main --no-progress
97
+ airev review --base main --no-progress
98
98
  """
99
99
  workdir = workdir or Path.cwd()
100
100
  start_time = time.perf_counter()
@@ -232,7 +232,7 @@ def runners():
232
232
 
233
233
  @main.command()
234
234
  def upgrade():
235
- """Atualiza o code-reviewer para a versão mais recente."""
235
+ """Atualiza o airev para a versão mais recente."""
236
236
  from rich.console import Console
237
237
 
238
238
  console = Console()
@@ -0,0 +1,61 @@
1
+ # English translations
2
+
3
+ cli:
4
+ # Analysis messages
5
+ analyzing: "Analyzing: [bold]{branch}[/bold] → [bold]{base}[/bold]"
6
+ getting_diff: "Getting diff..."
7
+ analyzing_diff: "Analyzing diff..."
8
+ building_context: "Building context..."
9
+ building_prompt: "Building prompt..."
10
+ running_analysis: "Running analysis with {runner}..."
11
+ processing_response: "Processing response..."
12
+ analysis_complete: "Analysis completed in {elapsed:.1f}s"
13
+
14
+ # Error messages
15
+ error_branch: "Error getting current branch: {error}"
16
+ error_diff: "Error getting diff: {error}"
17
+ error_diff_help: "Check if branch '{base}' exists and you're in a git repository."
18
+ error_runner_invalid: "Invalid runner: {error}"
19
+ error_runner_unavailable: "Runner '{runner}' is not available."
20
+ error_runner_help: "Check if the CLI is installed and configured."
21
+ error_runner_not_found: "Runner not found: {error}"
22
+ error_execution: "Execution error: {error}"
23
+
24
+ # Warning messages
25
+ no_changes: "No changes found in diff."
26
+ no_files: "No relevant files to analyze."
27
+
28
+ # Dependencies
29
+ dependencies_found: "Dependencies found:"
30
+
31
+ progress:
32
+ # Summary labels
33
+ modified_files: "Modified files:"
34
+ files_label: "Files:"
35
+ lines_label: "Lines:"
36
+ no_dependencies: "No dependencies found"
37
+ callers: "Callers:"
38
+ callees: "Callees:"
39
+ more: "+{count} more"
40
+
41
+ terminal:
42
+ # Header
43
+ code_review: "CODE REVIEW"
44
+ compared_with: "Compared with:"
45
+ files_count: "{count} file(s)"
46
+
47
+ # Findings
48
+ suggestion: "Suggestion:"
49
+
50
+ # Summary
51
+ summary: "SUMMARY:"
52
+ findings_count: "{count} finding(s)"
53
+ no_problems: "✓ No issues found. Code approved!"
54
+ raw_response: "AI raw response:"
55
+
56
+ parser:
57
+ # Fallback
58
+ unstructured_response: "Unstructured response"
59
+ unstructured_description: "The AI returned text not formatted as JSON"
60
+ unstructured_suggestion: "Check the raw response for details"
61
+ no_title: "No title"
@@ -0,0 +1,61 @@
1
+ # Traduções em Português Brasileiro (padrão)
2
+
3
+ cli:
4
+ # Mensagens de análise
5
+ analyzing: "Analisando: [bold]{branch}[/bold] → [bold]{base}[/bold]"
6
+ getting_diff: "Obtendo diff..."
7
+ analyzing_diff: "Analisando diff..."
8
+ building_context: "Construindo contexto..."
9
+ building_prompt: "Montando prompt..."
10
+ running_analysis: "Executando análise com {runner}..."
11
+ processing_response: "Processando resposta..."
12
+ analysis_complete: "Análise concluída em {elapsed:.1f}s"
13
+
14
+ # Mensagens de erro
15
+ error_branch: "Erro ao obter branch atual: {error}"
16
+ error_diff: "Erro ao obter diff: {error}"
17
+ error_diff_help: "Verifique se a branch '{base}' existe e se você está em um repositório git."
18
+ error_runner_invalid: "Runner inválido: {error}"
19
+ error_runner_unavailable: "Runner '{runner}' não está disponível."
20
+ error_runner_help: "Verifique se o CLI está instalado e configurado."
21
+ error_runner_not_found: "Runner não encontrado: {error}"
22
+ error_execution: "Erro na execução: {error}"
23
+
24
+ # Mensagens de aviso
25
+ no_changes: "Nenhuma mudança encontrada no diff."
26
+ no_files: "Nenhum arquivo relevante para analisar."
27
+
28
+ # Dependências
29
+ dependencies_found: "Dependências encontradas:"
30
+
31
+ progress:
32
+ # Labels de resumo
33
+ modified_files: "Arquivos modificados:"
34
+ files_label: "Arquivos:"
35
+ lines_label: "Linhas:"
36
+ no_dependencies: "Sem dependências encontradas"
37
+ callers: "Callers:"
38
+ callees: "Callees:"
39
+ more: "+{count} mais"
40
+
41
+ terminal:
42
+ # Header
43
+ code_review: "CODE REVIEW"
44
+ compared_with: "Comparado com:"
45
+ files_count: "{count} arquivo(s)"
46
+
47
+ # Findings
48
+ suggestion: "Sugestão:"
49
+
50
+ # Resumo
51
+ summary: "RESUMO:"
52
+ findings_count: "{count} finding(s)"
53
+ no_problems: "✓ Nenhum problema encontrado. Código aprovado!"
54
+ raw_response: "Resposta raw da IA:"
55
+
56
+ parser:
57
+ # Fallback
58
+ unstructured_response: "Resposta não estruturada"
59
+ unstructured_description: "A IA retornou texto não formatado como JSON"
60
+ unstructured_suggestion: "Verifique a resposta raw para detalhes"
61
+ no_title: "Sem título"
@@ -1,11 +1,12 @@
1
1
  """Módulo de auto-update para verificação e atualização de versões."""
2
2
 
3
- from .version_check import check_for_update, UpdateInfo
3
+ from .version_check import check_for_update, clear_cache, UpdateInfo
4
4
  from .notifier import notify_update
5
5
  from .upgrade import detect_installer, run_upgrade
6
6
 
7
7
  __all__ = [
8
8
  "check_for_update",
9
+ "clear_cache",
9
10
  "UpdateInfo",
10
11
  "notify_update",
11
12
  "detect_installer",
@@ -30,7 +30,7 @@ class UrllibClient:
30
30
  try:
31
31
  request = urllib.request.Request(
32
32
  url,
33
- headers={"Accept": "application/json", "User-Agent": "code-reviewer"},
33
+ headers={"Accept": "application/json", "User-Agent": "airev"},
34
34
  )
35
35
  with urllib.request.urlopen(request, timeout=timeout) as response:
36
36
  data = response.read().decode("utf-8")
@@ -1,5 +1,6 @@
1
1
  """Funcionalidades de upgrade do pacote."""
2
2
 
3
+ import json
3
4
  import subprocess
4
5
  import sys
5
6
  from pathlib import Path
@@ -7,7 +8,7 @@ from pathlib import Path
7
8
  from rich.console import Console
8
9
 
9
10
  from .. import __version__
10
- from .version_check import check_for_update
11
+ from .version_check import check_for_update, clear_cache
11
12
 
12
13
 
13
14
  def detect_installer() -> str:
@@ -25,6 +26,78 @@ def detect_installer() -> str:
25
26
  return "pip"
26
27
 
27
28
 
29
+ def get_installed_version(installer: str) -> str | None:
30
+ """Obtém a versão real instalada do airev consultando o instalador.
31
+
32
+ Args:
33
+ installer: "pipx" ou "pip"
34
+
35
+ Returns:
36
+ String com a versão instalada ou None se não conseguir obter
37
+ """
38
+ try:
39
+ if installer == "pipx":
40
+ # Tenta usar pipx list --json
41
+ result = subprocess.run(
42
+ ["pipx", "list", "--json"],
43
+ capture_output=True,
44
+ text=True,
45
+ check=False,
46
+ )
47
+ if result.returncode == 0:
48
+ data = json.loads(result.stdout)
49
+ venvs = data.get("venvs", {})
50
+ if "airev" in venvs:
51
+ metadata = venvs["airev"].get("metadata", {})
52
+ return metadata.get("main_package", {}).get("package_version")
53
+ # Fallback: tenta sem --json (versões antigas do pipx)
54
+ return _get_version_from_pipx_list_text()
55
+ else:
56
+ # pip show airev
57
+ result = subprocess.run(
58
+ [sys.executable, "-m", "pip", "show", "airev"],
59
+ capture_output=True,
60
+ text=True,
61
+ check=False,
62
+ )
63
+ if result.returncode == 0:
64
+ for line in result.stdout.splitlines():
65
+ if line.startswith("Version:"):
66
+ return line.split(":", 1)[1].strip()
67
+ except (subprocess.SubprocessError, json.JSONDecodeError, KeyError):
68
+ pass
69
+ return None
70
+
71
+
72
+ def _get_version_from_pipx_list_text() -> str | None:
73
+ """Fallback para obter versão do pipx list sem --json.
74
+
75
+ Returns:
76
+ String com a versão ou None se não encontrar
77
+ """
78
+ try:
79
+ result = subprocess.run(
80
+ ["pipx", "list"],
81
+ capture_output=True,
82
+ text=True,
83
+ check=False,
84
+ )
85
+ if result.returncode == 0:
86
+ # Procura por linha como "airev 1.0.0" ou "package airev 1.0.0"
87
+ for line in result.stdout.splitlines():
88
+ if "airev" in line.lower():
89
+ parts = line.split()
90
+ for i, part in enumerate(parts):
91
+ if "airev" in part.lower() and i + 1 < len(parts):
92
+ version = parts[i + 1].strip(",")
93
+ # Verifica se parece uma versão
94
+ if version and version[0].isdigit():
95
+ return version
96
+ except subprocess.SubprocessError:
97
+ pass
98
+ return None
99
+
100
+
28
101
  def run_upgrade(console: Console | None = None) -> bool:
29
102
  """Executa upgrade do pacote.
30
103
 
@@ -32,7 +105,7 @@ def run_upgrade(console: Console | None = None) -> bool:
32
105
  console: Console Rich para output (opcional)
33
106
 
34
107
  Returns:
35
- True se upgrade foi executado, False se já está atualizado ou falhou
108
+ True se upgrade foi executado com sucesso, False caso contrário
36
109
  """
37
110
  if console is None:
38
111
  console = Console()
@@ -42,14 +115,20 @@ def run_upgrade(console: Console | None = None) -> bool:
42
115
  update_info = check_for_update()
43
116
 
44
117
  if update_info is None:
118
+ # Limpa cache mesmo quando não há atualização (garante consistência)
119
+ clear_cache()
45
120
  console.print(
46
121
  f"[green]✓[/] Você já está na versão mais recente ([cyan]{__version__}[/])"
47
122
  )
48
123
  return False
49
124
 
50
125
  installer = detect_installer()
126
+
127
+ # Obtém versão antes do upgrade para comparação
128
+ version_before = get_installed_version(installer) or __version__
129
+
51
130
  console.print(
52
- f"[yellow]→[/] Atualizando de {update_info.current_version} "
131
+ f"[yellow]→[/] Atualizando de {version_before} "
53
132
  f"para {update_info.latest_version}..."
54
133
  )
55
134
 
@@ -67,21 +146,37 @@ def run_upgrade(console: Console | None = None) -> bool:
67
146
  check=False,
68
147
  )
69
148
 
149
+ # Sempre limpa o cache após tentativa de upgrade
150
+ clear_cache()
151
+
70
152
  if result.returncode == 0:
71
- console.print(
72
- f"[green]✓[/] Atualizado para versão {update_info.latest_version}"
73
- )
74
- return True
153
+ # Verifica se a versão realmente mudou
154
+ version_after = get_installed_version(installer)
155
+
156
+ if version_after and version_after != version_before:
157
+ console.print(
158
+ f"[green]✓[/] Atualizado de {version_before} para {version_after}"
159
+ )
160
+ return True
161
+ else:
162
+ # Comando executou mas versão não mudou
163
+ console.print(
164
+ f"[green]✓[/] Você já está na versão mais recente "
165
+ f"([cyan]{version_after or version_before}[/])"
166
+ )
167
+ return False
75
168
  else:
76
169
  console.print(f"[red]✗[/] Falha ao atualizar: {result.stderr.strip()}")
77
170
  console.print(f"[dim]Tente manualmente: {' '.join(cmd)}[/]")
78
171
  return False
79
172
 
80
173
  except FileNotFoundError:
174
+ clear_cache()
81
175
  console.print(f"[red]✗[/] Comando '{cmd[0]}' não encontrado")
82
176
  if installer == "pipx":
83
177
  console.print("[dim]Tente: pip install --upgrade airev[/]")
84
178
  return False
85
179
  except Exception as e:
180
+ clear_cache()
86
181
  console.print(f"[red]✗[/] Erro inesperado: {e}")
87
182
  return False
@@ -110,6 +110,24 @@ def _write_cache(latest_version: str) -> None:
110
110
  pass
111
111
 
112
112
 
113
+ def clear_cache() -> bool:
114
+ """Remove o arquivo de cache de verificação de versão.
115
+
116
+ Deve ser chamada após upgrade para garantir que a próxima
117
+ verificação consulte o PyPI novamente.
118
+
119
+ Returns:
120
+ True se o cache foi removido ou não existia, False se falhou
121
+ """
122
+ try:
123
+ if CACHE_FILE.exists():
124
+ CACHE_FILE.unlink()
125
+ return True
126
+ except OSError:
127
+ # Falha ao remover cache - ignora silenciosamente
128
+ return False
129
+
130
+
113
131
  def get_latest_version(timeout: float = DEFAULT_TIMEOUT) -> str | None:
114
132
  """Consulta PyPI para obter a versão mais recente.
115
133
 
File without changes