neo-cmd 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.
neo_cmd-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thalyson Wilker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
neo_cmd-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: neo-cmd
3
+ Version: 0.1.0
4
+ Summary: Personal Command Assistant — Compreenda seus sistemas. Seja dono das suas escolhas.
5
+ Keywords: cli,assistant,github,bitbucket,shortcut,kanban,productivity,typer
6
+ Author: Thalyson
7
+ Author-email: Thalyson <thalison.wilker@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Version Control :: Git
17
+ Classifier: Topic :: Utilities
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: httpx>=0.28.1
20
+ Requires-Dist: keyring>=25.7.0
21
+ Requires-Dist: pydantic>=2.14.1
22
+ Requires-Dist: rich>=15.0.0
23
+ Requires-Dist: typer>=0.27.3
24
+ Requires-Python: >=3.13
25
+ Project-URL: Homepage, https://github.com/thalisonwilker/neo
26
+ Project-URL: Documentation, https://thalisonwilker.github.io/neo/
27
+ Project-URL: Repository, https://github.com/thalisonwilker/neo
28
+ Project-URL: Issues, https://github.com/thalisonwilker/neo/issues
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Neo — Personal Command Assistant
32
+
33
+ > **Compreenda seus sistemas. Seja dono das suas escolhas.**
34
+
35
+ <p align="center">
36
+ <img src="https://raw.githubusercontent.com/thalisonwilker/neo/main/docs/assets/neo-logo.jpg" alt="Neo CLI Logo" width="240" style="border-radius: 20px;" />
37
+ </p>
38
+
39
+ <p align="center">
40
+ <em>Assistente pessoal de linha de comando, alta produtividade, modular, seguro e pronto para automação</em>
41
+ </p>
42
+
43
+ <p align="center">
44
+ <a href="https://github.com/thalisonwilker/neo/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://github.com/thalisonwilker/neo/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI & Deploy" /></a>
45
+ <a href="https://thalisonwilker.github.io/neo/"><img src="https://img.shields.io/endpoint?url=https://thalisonwilker.github.io/neo/coverage-badge.json" alt="Coverage" /></a>
46
+ <a href="https://pypi.org/project/neo-cmd/"><img src="https://img.shields.io/badge/pypi%20package-v0.1.0-34D058" alt="PyPI Package" /></a>
47
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.13+-34D058" alt="Python 3.13+" /></a>
48
+ <a href="https://github.com/thalisonwilker/neo/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-34D058" alt="License: MIT" /></a>
49
+ </p>
50
+
51
+ **Neo** (`neo-cmd`) é um assistente pessoal extensível de linha de comando desenvolvido em **Python 3.13** com **Typer** e **Rich**. Ele centraliza operações de repositórios Git (**GitHub** e **Bitbucket Cloud**) e gestão de demandas (**Shortcut**), oferecendo quadros Kanban no terminal, análise de contexto, segurança nativa via Keyring do SO e suporte a `--json`.
52
+
53
+ 📚 **Documentação Completa:** **[thalisonwilker.github.io/neo](https://thalisonwilker.github.io/neo/)**
54
+
55
+ ---
56
+
57
+ ## 🚀 Instalação
58
+
59
+ ### Via PyPI (`uv` ou `pip`)
60
+
61
+ ```bash
62
+ # Recomendado: instalar globalmente como ferramenta isolada com uv
63
+ uv tool install neo-cmd
64
+
65
+ # Ou via pip
66
+ pip install neo-cmd
67
+ ```
68
+
69
+ ### Desenvolvimento Local
70
+
71
+ ```bash
72
+ git clone https://github.com/thalisonwilker/neo.git
73
+ cd neo
74
+ uv sync
75
+ uv run neo --help
76
+ ```
77
+
78
+ ---
79
+
80
+ ## ⚡ Uso Rápido
81
+
82
+ ```bash
83
+ # 1. Configurar credenciais com segurança no Keyring do SO
84
+ neo git config auth set github
85
+ neo tasks config set
86
+
87
+ # 2. Quadro Kanban no terminal (A fazer | Fazendo | Feito) da iteração atual
88
+ neo tasks resume
89
+
90
+ # 3. Consultar e analisar stories / chamados
91
+ neo tasks list --mine
92
+ neo tasks analyze 2108
93
+
94
+ # 4. Gerenciar workspaces, repositórios e histórico Git (GitHub / Bitbucket)
95
+ neo git workspace select
96
+ neo git repo list
97
+ neo git commits search --query "fix" --limit 5
98
+
99
+ # 5. Status geral de todas as integrações
100
+ neo config show
101
+ ```
102
+
103
+ > Todos os comandos aceitam a flag global `--json` (ex.: `neo --json tasks resume`) para integração com `jq` e pipelines de automação.
104
+
105
+ ---
106
+
107
+ ## 🛠️ Qualidade & Testes
108
+
109
+ ```bash
110
+ uv run pytest --cov=neo # Testes unitários e E2E (cobertura >= 80%)
111
+ uv run ruff check . # Linter e formatação
112
+ uv run mypy src # Checagem estática de tipos (strict)
113
+ ```
114
+
115
+ ---
116
+
117
+ ## 📄 Licença
118
+
119
+ Distribuído sob a licença livre **MIT**. Consulte o arquivo [LICENSE](https://github.com/thalisonwilker/neo/blob/main/LICENSE) para mais detalhes.
@@ -0,0 +1,89 @@
1
+ # Neo — Personal Command Assistant
2
+
3
+ > **Compreenda seus sistemas. Seja dono das suas escolhas.**
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/thalisonwilker/neo/main/docs/assets/neo-logo.jpg" alt="Neo CLI Logo" width="240" style="border-radius: 20px;" />
7
+ </p>
8
+
9
+ <p align="center">
10
+ <em>Assistente pessoal de linha de comando, alta produtividade, modular, seguro e pronto para automação</em>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="https://github.com/thalisonwilker/neo/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://github.com/thalisonwilker/neo/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI & Deploy" /></a>
15
+ <a href="https://thalisonwilker.github.io/neo/"><img src="https://img.shields.io/endpoint?url=https://thalisonwilker.github.io/neo/coverage-badge.json" alt="Coverage" /></a>
16
+ <a href="https://pypi.org/project/neo-cmd/"><img src="https://img.shields.io/badge/pypi%20package-v0.1.0-34D058" alt="PyPI Package" /></a>
17
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.13+-34D058" alt="Python 3.13+" /></a>
18
+ <a href="https://github.com/thalisonwilker/neo/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-34D058" alt="License: MIT" /></a>
19
+ </p>
20
+
21
+ **Neo** (`neo-cmd`) é um assistente pessoal extensível de linha de comando desenvolvido em **Python 3.13** com **Typer** e **Rich**. Ele centraliza operações de repositórios Git (**GitHub** e **Bitbucket Cloud**) e gestão de demandas (**Shortcut**), oferecendo quadros Kanban no terminal, análise de contexto, segurança nativa via Keyring do SO e suporte a `--json`.
22
+
23
+ 📚 **Documentação Completa:** **[thalisonwilker.github.io/neo](https://thalisonwilker.github.io/neo/)**
24
+
25
+ ---
26
+
27
+ ## 🚀 Instalação
28
+
29
+ ### Via PyPI (`uv` ou `pip`)
30
+
31
+ ```bash
32
+ # Recomendado: instalar globalmente como ferramenta isolada com uv
33
+ uv tool install neo-cmd
34
+
35
+ # Ou via pip
36
+ pip install neo-cmd
37
+ ```
38
+
39
+ ### Desenvolvimento Local
40
+
41
+ ```bash
42
+ git clone https://github.com/thalisonwilker/neo.git
43
+ cd neo
44
+ uv sync
45
+ uv run neo --help
46
+ ```
47
+
48
+ ---
49
+
50
+ ## ⚡ Uso Rápido
51
+
52
+ ```bash
53
+ # 1. Configurar credenciais com segurança no Keyring do SO
54
+ neo git config auth set github
55
+ neo tasks config set
56
+
57
+ # 2. Quadro Kanban no terminal (A fazer | Fazendo | Feito) da iteração atual
58
+ neo tasks resume
59
+
60
+ # 3. Consultar e analisar stories / chamados
61
+ neo tasks list --mine
62
+ neo tasks analyze 2108
63
+
64
+ # 4. Gerenciar workspaces, repositórios e histórico Git (GitHub / Bitbucket)
65
+ neo git workspace select
66
+ neo git repo list
67
+ neo git commits search --query "fix" --limit 5
68
+
69
+ # 5. Status geral de todas as integrações
70
+ neo config show
71
+ ```
72
+
73
+ > Todos os comandos aceitam a flag global `--json` (ex.: `neo --json tasks resume`) para integração com `jq` e pipelines de automação.
74
+
75
+ ---
76
+
77
+ ## 🛠️ Qualidade & Testes
78
+
79
+ ```bash
80
+ uv run pytest --cov=neo # Testes unitários e E2E (cobertura >= 80%)
81
+ uv run ruff check . # Linter e formatação
82
+ uv run mypy src # Checagem estática de tipos (strict)
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 📄 Licença
88
+
89
+ Distribuído sob a licença livre **MIT**. Consulte o arquivo [LICENSE](https://github.com/thalisonwilker/neo/blob/main/LICENSE) para mais detalhes.
@@ -0,0 +1,88 @@
1
+ [project]
2
+ name = "neo-cmd"
3
+ version = "0.1.0"
4
+ description = "Personal Command Assistant — Compreenda seus sistemas. Seja dono das suas escolhas."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.13"
9
+ keywords = [
10
+ "cli",
11
+ "assistant",
12
+ "github",
13
+ "bitbucket",
14
+ "shortcut",
15
+ "kanban",
16
+ "productivity",
17
+ "typer",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Environment :: Console",
22
+ "Intended Audience :: Developers",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Version Control :: Git",
27
+ "Topic :: Utilities",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = [
31
+ "httpx>=0.28.1",
32
+ "keyring>=25.7.0",
33
+ "pydantic>=2.14.1",
34
+ "rich>=15.0.0",
35
+ "typer>=0.27.3",
36
+ ]
37
+
38
+ [[project.authors]]
39
+ name = "Thalyson"
40
+ email = "thalison.wilker@gmail.com"
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/thalisonwilker/neo"
44
+ Documentation = "https://thalisonwilker.github.io/neo/"
45
+ Repository = "https://github.com/thalisonwilker/neo"
46
+ Issues = "https://github.com/thalisonwilker/neo/issues"
47
+
48
+ [project.scripts]
49
+ neo = "neo.cli:app"
50
+
51
+ [build-system]
52
+ requires = ["uv_build>=0.13.5,<0.14.0"]
53
+ build-backend = "uv_build"
54
+
55
+ [tool.uv.build-backend]
56
+ module-name = "neo"
57
+
58
+ [tool.ruff]
59
+ line-length = 100
60
+ target-version = "py313"
61
+
62
+ [tool.mypy]
63
+ python_version = "3.13"
64
+ strict = true
65
+ warn_unused_configs = true
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ pythonpath = ["src"]
70
+
71
+ [tool.coverage.run]
72
+ data_file = ".pytest_cache/.coverage"
73
+
74
+ [dependency-groups]
75
+ dev = [
76
+ "mypy>=2.4.0",
77
+ "pytest>=9.1.1",
78
+ "pytest-cov>=7.1.0",
79
+ "pyyaml>=6.0.2",
80
+ "respx>=0.23.1",
81
+ "ruff>=0.17.3",
82
+ "types-pyyaml>=6.0.12",
83
+ ]
84
+ docs = [
85
+ "mkdocs>=1.6.1",
86
+ "mkdocs-material>=9.6.7",
87
+ "pymdown-extensions>=10.14.3",
88
+ ]
@@ -0,0 +1,88 @@
1
+ [project]
2
+ name = "neo-cmd"
3
+ version = "0.1.0"
4
+ description = "Personal Command Assistant — Compreenda seus sistemas. Seja dono das suas escolhas."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "Thalyson", email = "thalison.wilker@gmail.com" }
10
+ ]
11
+ requires-python = ">=3.13"
12
+ keywords = [
13
+ "cli",
14
+ "assistant",
15
+ "github",
16
+ "bitbucket",
17
+ "shortcut",
18
+ "kanban",
19
+ "productivity",
20
+ "typer",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Environment :: Console",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Topic :: Software Development :: Version Control :: Git",
30
+ "Topic :: Utilities",
31
+ "Typing :: Typed",
32
+ ]
33
+ dependencies = [
34
+ "httpx>=0.28.1",
35
+ "keyring>=25.7.0",
36
+ "pydantic>=2.14.1",
37
+ "rich>=15.0.0",
38
+ "typer>=0.27.3",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/thalisonwilker/neo"
43
+ Documentation = "https://thalisonwilker.github.io/neo/"
44
+ Repository = "https://github.com/thalisonwilker/neo"
45
+ Issues = "https://github.com/thalisonwilker/neo/issues"
46
+
47
+ [build-system]
48
+ requires = ["uv_build>=0.13.5,<0.14.0"]
49
+ build-backend = "uv_build"
50
+
51
+ [tool.uv.build-backend]
52
+ module-name = "neo"
53
+
54
+ [dependency-groups]
55
+ dev = [
56
+ "mypy>=2.4.0",
57
+ "pytest>=9.1.1",
58
+ "pytest-cov>=7.1.0",
59
+ "pyyaml>=6.0.2",
60
+ "respx>=0.23.1",
61
+ "ruff>=0.17.3",
62
+ "types-pyyaml>=6.0.12",
63
+ ]
64
+ docs = [
65
+ "mkdocs>=1.6.1",
66
+ "mkdocs-material>=9.6.7",
67
+ "pymdown-extensions>=10.14.3",
68
+ ]
69
+
70
+ [project.scripts]
71
+ neo = "neo.cli:app"
72
+
73
+ [tool.ruff]
74
+ line-length = 100
75
+ target-version = "py313"
76
+
77
+ [tool.mypy]
78
+ python_version = "3.13"
79
+ strict = true
80
+ warn_unused_configs = true
81
+
82
+ [tool.pytest.ini_options]
83
+ testpaths = ["tests"]
84
+ pythonpath = ["src"]
85
+
86
+ [tool.coverage.run]
87
+ data_file = ".pytest_cache/.coverage"
88
+
@@ -0,0 +1,2 @@
1
+ def hello() -> str:
2
+ return "Hello from neo!"
@@ -0,0 +1,76 @@
1
+ """Entrypoint principal da CLI Neo."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ import typer
8
+ from rich import print as rprint
9
+
10
+ from neo.commands.config import config_app
11
+ from neo.commands.git import git_app
12
+ from neo.commands.tasks import tasks_app
13
+
14
+ __version__ = "0.1.0"
15
+
16
+
17
+ @dataclass
18
+ class AppContext:
19
+ json_mode: bool = False
20
+ verbose: bool = False
21
+
22
+
23
+ app = typer.Typer(
24
+ name="neo",
25
+ help="""[bold cyan]Neo — Personal Command Assistant[/bold cyan]
26
+
27
+ Compreenda seus sistemas. Seja dono das suas escolhas.
28
+
29
+ Centraliza operações de trabalho (Bitbucket, Shortcut) e vida pessoal,
30
+ investigando dados com autonomia e sem atrito.
31
+ """,
32
+ no_args_is_help=True,
33
+ rich_markup_mode="rich",
34
+ )
35
+
36
+ # Registra subcomandos
37
+ app.add_typer(config_app, name="config")
38
+ app.add_typer(git_app, name="git")
39
+ app.add_typer(tasks_app, name="tasks")
40
+
41
+
42
+ def version_callback(value: bool) -> None:
43
+ if value:
44
+ rprint(f"[bold cyan]Neo[/bold cyan] v{__version__}")
45
+ raise typer.Exit()
46
+
47
+
48
+ @app.callback()
49
+ def main(
50
+ ctx: typer.Context,
51
+ version: bool | None = typer.Option(
52
+ None,
53
+ "--version",
54
+ "-V",
55
+ help="Exibe a versão do Neo e encerra.",
56
+ callback=version_callback,
57
+ is_eager=True,
58
+ ),
59
+ json_mode: bool = typer.Option(
60
+ False,
61
+ "--json",
62
+ help="Emite a saída em formato JSON estruturado no stdout.",
63
+ ),
64
+ verbose: bool = typer.Option(
65
+ False,
66
+ "--verbose",
67
+ "-v",
68
+ help="Habilita mensagens de debug e detalhes de rede.",
69
+ ),
70
+ ) -> None:
71
+ """Configura o contexto global da aplicação."""
72
+ ctx.obj = AppContext(json_mode=json_mode, verbose=verbose)
73
+
74
+
75
+ if __name__ == "__main__":
76
+ app()
@@ -0,0 +1 @@
1
+ """Comandos da CLI do Neo."""
@@ -0,0 +1,105 @@
1
+ """Operações de credenciais compartilhadas por `neo git config auth` e `neo tasks config`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+ from keyring.errors import KeyringError
7
+
8
+ from neo.config import (
9
+ delete_credential,
10
+ get_credential,
11
+ get_credential_source,
12
+ mask_token,
13
+ set_credential,
14
+ )
15
+ from neo.output import print_error, print_json, print_panel, print_success
16
+
17
+
18
+ def is_json_mode(ctx: typer.Context) -> bool:
19
+ return getattr(ctx.obj, "json_mode", False) if ctx.obj else False
20
+
21
+
22
+ def save_token(ctx: typer.Context, svc: str, token: str | None) -> None:
23
+ """Grava o token de `svc` (prompt oculto se `token` for omitido)."""
24
+ as_json = is_json_mode(ctx)
25
+
26
+ if not token:
27
+ if as_json:
28
+ print_error(
29
+ "A flag --token é obrigatória quando o modo --json está ativo.",
30
+ as_json=True,
31
+ code=1,
32
+ )
33
+ raise typer.Exit(code=1)
34
+ token = typer.prompt(f"Digite o token para '{svc}'", hide_input=True)
35
+
36
+ try:
37
+ set_credential(svc, token)
38
+ source = get_credential_source(svc)
39
+ print_success(
40
+ f"Token para o serviço '{svc}' configurado com sucesso (armazenado via {source})!",
41
+ as_json=as_json,
42
+ json_payload={"status": "success", "service": svc, "source": source},
43
+ )
44
+ except (KeyringError, OSError, RuntimeError, ValueError) as e:
45
+ print_error(f"Falha ao salvar credencial: {e}", as_json=as_json, code=1)
46
+ raise typer.Exit(code=1) from e
47
+
48
+
49
+ def show_token(ctx: typer.Context, svc: str) -> None:
50
+ """Exibe o status e o token mascarado de `svc`."""
51
+ as_json = is_json_mode(ctx)
52
+ token = get_credential(svc)
53
+ source = get_credential_source(svc)
54
+
55
+ if not token:
56
+ print_error(
57
+ f"Serviço '{svc}' não possui credenciais configuradas.",
58
+ as_json=as_json,
59
+ json_payload={
60
+ "service": svc,
61
+ "configured": False,
62
+ "source": None,
63
+ "masked_token": None,
64
+ },
65
+ code=1,
66
+ )
67
+ raise typer.Exit(code=1)
68
+
69
+ masked = mask_token(token)
70
+ if as_json:
71
+ print_json(
72
+ {
73
+ "service": svc,
74
+ "configured": True,
75
+ "source": source,
76
+ "masked_token": masked,
77
+ }
78
+ )
79
+ else:
80
+ print_panel(
81
+ f"Autenticação: {svc}",
82
+ f"[bold]Status:[/bold] [green]Configurado[/green]\n"
83
+ f"[bold]Origem:[/bold] {source}\n"
84
+ f"[bold]Token:[/bold] {masked}",
85
+ )
86
+
87
+
88
+ def remove_token(ctx: typer.Context, svc: str) -> None:
89
+ """Remove a credencial armazenada de `svc`."""
90
+ as_json = is_json_mode(ctx)
91
+
92
+ if delete_credential(svc):
93
+ print_success(
94
+ f"Credencial para o serviço '{svc}' removida com sucesso.",
95
+ as_json=as_json,
96
+ json_payload={"status": "success", "service": svc, "deleted": True},
97
+ )
98
+ else:
99
+ print_error(
100
+ f"Nenhuma credencial encontrada para remover no serviço '{svc}'.",
101
+ as_json=as_json,
102
+ json_payload={"status": "error", "service": svc, "deleted": False},
103
+ code=1,
104
+ )
105
+ raise typer.Exit(code=1)
@@ -0,0 +1,95 @@
1
+ """Comandos de consulta e histórico de commits Git (Bitbucket e GitHub) (`neo git commits`)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+ from typer import Option
7
+
8
+ from neo.integrations.bitbucket import BitbucketError
9
+ from neo.integrations.resolver import (
10
+ detect_git_remote_info,
11
+ resolve_git_provider,
12
+ )
13
+ from neo.output import print_error, print_json, print_panel, print_table
14
+
15
+ commits_app = typer.Typer(
16
+ name="commits",
17
+ help="Histórico e pesquisa de commits no Bitbucket e GitHub.",
18
+ no_args_is_help=True,
19
+ )
20
+
21
+
22
+ def _infer_repo_slug_from_git() -> str | None:
23
+ """Tenta inferir o slug do repositório a partir do remote origin do diretório local."""
24
+ return detect_git_remote_info()[1]
25
+
26
+
27
+ @commits_app.command("search")
28
+ def commits_search(
29
+ ctx: typer.Context,
30
+ repo: str | None = Option(
31
+ None, "--repo", "-r", help="Slug do repositório (inferido do git local se omitido)."
32
+ ),
33
+ workspace: str | None = Option(
34
+ None, "--workspace", "-w", help="Workspace ou organização/usuário de destino."
35
+ ),
36
+ provider: str | None = Option(
37
+ None, "--provider", "-p", help="Provedor Git: 'bitbucket' ou 'github'."
38
+ ),
39
+ author: str | None = Option(None, "--author", "-a", help="Filtra por nome ou e-mail do autor."),
40
+ query: str | None = Option(
41
+ None, "--query", "-q", help="Filtra por termo na mensagem do commit."
42
+ ),
43
+ limit: int = Option(20, "--limit", "-l", help="Quantidade máxima de commits a retornar."),
44
+ ) -> None:
45
+ """Pesquisa commits em um repositório no Bitbucket ou GitHub."""
46
+ as_json = getattr(ctx.obj, "json_mode", False) if ctx.obj else False
47
+
48
+ target_repo = repo or _infer_repo_slug_from_git()
49
+ if not target_repo:
50
+ msg = (
51
+ "Repositório não informado e não foi possível inferir do git local. "
52
+ "Use a flag `--repo <slug>` para especificar o repositório."
53
+ )
54
+ print_error(msg, as_json=as_json, code=1)
55
+ raise typer.Exit(code=1)
56
+
57
+ prov_name, client = resolve_git_provider(provider, as_json=as_json)
58
+
59
+ try:
60
+ commits = client.list_commits(
61
+ repo_slug=target_repo,
62
+ workspace=workspace,
63
+ author=author,
64
+ query=query,
65
+ limit=limit,
66
+ )
67
+ except BitbucketError as e:
68
+ print_error(str(e), as_json=as_json, code=1)
69
+ raise typer.Exit(code=1) from e
70
+
71
+ if as_json:
72
+ print_json([c.model_dump() for c in commits])
73
+ else:
74
+ prov_title = "GitHub" if prov_name == "github" else "Bitbucket"
75
+ if not commits:
76
+ print_panel(
77
+ "Commits",
78
+ f"Nenhum commit encontrado para os filtros informados em '{target_repo}' ({prov_title}).",
79
+ )
80
+ return
81
+
82
+ columns = ["Hash", "Autor", "Data", "Mensagem"]
83
+ rows: list[list[str]] = []
84
+ for c in commits:
85
+ date_str = c.date.split("T")[0] if "T" in c.date else c.date
86
+ rows.append(
87
+ [
88
+ f"[bold yellow]{c.short_hash}[/bold yellow]",
89
+ c.author.author_name,
90
+ date_str,
91
+ c.summary,
92
+ ]
93
+ )
94
+
95
+ print_table(f"Histórico de Commits ({target_repo} via {prov_title})", columns, rows)