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 +21 -0
- neo_cmd-0.1.0/PKG-INFO +119 -0
- neo_cmd-0.1.0/README.md +89 -0
- neo_cmd-0.1.0/pyproject.toml +88 -0
- neo_cmd-0.1.0/pyproject.toml.orig +88 -0
- neo_cmd-0.1.0/src/neo/__init__.py +2 -0
- neo_cmd-0.1.0/src/neo/cli.py +76 -0
- neo_cmd-0.1.0/src/neo/commands/__init__.py +1 -0
- neo_cmd-0.1.0/src/neo/commands/_credentials.py +105 -0
- neo_cmd-0.1.0/src/neo/commands/commits.py +95 -0
- neo_cmd-0.1.0/src/neo/commands/config.py +58 -0
- neo_cmd-0.1.0/src/neo/commands/git.py +134 -0
- neo_cmd-0.1.0/src/neo/commands/repo.py +214 -0
- neo_cmd-0.1.0/src/neo/commands/tasks.py +722 -0
- neo_cmd-0.1.0/src/neo/commands/workspace.py +204 -0
- neo_cmd-0.1.0/src/neo/config.py +380 -0
- neo_cmd-0.1.0/src/neo/integrations/__init__.py +1 -0
- neo_cmd-0.1.0/src/neo/integrations/bitbucket.py +217 -0
- neo_cmd-0.1.0/src/neo/integrations/bitbucket_models.py +154 -0
- neo_cmd-0.1.0/src/neo/integrations/github.py +232 -0
- neo_cmd-0.1.0/src/neo/integrations/github_models.py +68 -0
- neo_cmd-0.1.0/src/neo/integrations/resolver.py +150 -0
- neo_cmd-0.1.0/src/neo/integrations/shortcut.py +210 -0
- neo_cmd-0.1.0/src/neo/integrations/shortcut_models.py +210 -0
- neo_cmd-0.1.0/src/neo/output.py +58 -0
- neo_cmd-0.1.0/src/neo/py.typed +0 -0
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.
|
neo_cmd-0.1.0/README.md
ADDED
|
@@ -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,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)
|