manage-project-tool 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.
@@ -0,0 +1,76 @@
1
+ # ManageProjectTool .gitignore
2
+
3
+ # Node
4
+ node_modules/
5
+ npm-debug.log*
6
+ yarn-debug.log*
7
+ yarn-error.log*
8
+ pnpm-debug.log*
9
+ .pnp.*
10
+
11
+ # Logs
12
+ logs/
13
+ *.log
14
+ *.log.*
15
+
16
+ # Runtime / environment
17
+ .env
18
+ .env.*
19
+
20
+ # Build outputs
21
+ dist/
22
+ build/
23
+
24
+ # Coverage
25
+ coverage/
26
+ .nyc_output/
27
+ htmlcov/
28
+
29
+ # Python
30
+ .venv/
31
+ venv/
32
+ ENV/
33
+ env/
34
+ __pycache__/
35
+ *.py[cod]
36
+ *$py.class
37
+ .pytest_cache/
38
+ .mypy_cache/
39
+ .coverage
40
+ pip-wheel-metadata/
41
+ *.egg-info/
42
+ .eggs/
43
+ *.egg
44
+ *.whl
45
+
46
+ # PyInstaller
47
+ __pycache__/
48
+ dist/
49
+ build/
50
+
51
+ # Caches
52
+ .cache/
53
+
54
+ # IDEs and editors
55
+ .vscode/
56
+ .idea/
57
+ *.suo
58
+ *.ntvs*
59
+ *.njsproj
60
+ *.sln
61
+ *.swp
62
+ *~
63
+ *.tmp
64
+ *.bak
65
+
66
+ # OS files
67
+ .DS_Store
68
+ Thumbs.db
69
+ desktop.ini
70
+
71
+ # Lint / tooling
72
+ .eslintcache
73
+
74
+ # Other
75
+ node-repl.history
76
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jaminsmoke
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.
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.4
2
+ Name: manage-project-tool
3
+ Version: 0.1.0
4
+ Summary: Python engine for ManageProjectTool — audits and manages repositories
5
+ Project-URL: Homepage, https://github.com/jaminsmoke/ManageProjectTool
6
+ Project-URL: Repository, https://github.com/jaminsmoke/ManageProjectTool
7
+ Project-URL: Issues, https://github.com/jaminsmoke/ManageProjectTool/issues
8
+ Author: jaminsmoke
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: manageprojecttool,mpt,project-audit,static-analysis
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+
23
+ # ManageProjectTool
24
+
25
+ ManageProjectTool audita repositorios con un engine Python, un coordinator
26
+ Node.js, una app Electron y una GitHub Action reutilizable para CI.
27
+
28
+ ## Capacidades actuales
29
+
30
+ - Ejecuta checks core y plugins sobre documentación, CI, dependencias y seguridad.
31
+ - Aplica severidades efectivas (`error`, `warning`, `info`) y umbrales como
32
+ `thresholds.maxWarnings` desde `mpt.config.json`.
33
+ - Expone un CLI standalone con `mpt scan` y `mpt init`.
34
+ - Genera reportes en JSON, HTML y Markdown según el flujo de uso.
35
+
36
+ ## Uso local
37
+
38
+ ### CLI Python
39
+
40
+ ```bash
41
+ python -m engine.cli scan .
42
+ python -m engine.cli scan . --format json
43
+ python -m engine.cli init .
44
+ ```
45
+
46
+ ### Validación del workspace
47
+
48
+ ```bash
49
+ npm install
50
+ npm run validate
51
+ ```
52
+
53
+ `npm run validate` ejecuta formato, linters y tests en secuencia.
54
+
55
+ ### Preparación de release (Fase B)
56
+
57
+ ```bash
58
+ npm run release:check
59
+ ```
60
+
61
+ Este comando valida prerequisitos implementables en el repo para `v0.1.0`
62
+ (`LICENSE`, artefactos de Action y assets de Electron) y lista pendientes
63
+ externos como Trusted Publisher en PyPI, `NPM_TOKEN` y Marketplace.
64
+
65
+ ## GitHub Action
66
+
67
+ La Action Docker definida en la raíz permite reutilizar el engine sin levantar
68
+ el coordinator.
69
+
70
+ ```yaml
71
+ name: Scan repository
72
+
73
+ on:
74
+ pull_request:
75
+ workflow_dispatch:
76
+
77
+ jobs:
78
+ scan:
79
+ runs-on: ubuntu-latest
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+ - name: Run ManageProjectTool
83
+ id: mpt
84
+ uses: jaminsmoke/ManageProjectTool@v0.1.0
85
+ with:
86
+ target-path: .
87
+ format: markdown
88
+ checks: readme-presence,lockfile,ci-workflow-presence
89
+ - name: Upload report
90
+ if: always()
91
+ uses: actions/upload-artifact@v4
92
+ with:
93
+ name: mpt-report
94
+ path: ${{ steps.mpt.outputs.report-path }}
95
+ ```
96
+
97
+ Entradas soportadas:
98
+
99
+ - `target-path`: ruta relativa dentro de `GITHUB_WORKSPACE`.
100
+ - `checks`: lista separada por comas; vacía usa `mpt.config.json` o todos los checks.
101
+ - `format`: `markdown` o `json`.
102
+
103
+ Salidas expuestas:
104
+
105
+ - `report-path`: fichero generado en `reports/`.
106
+ - `exit-code`: resultado efectivo de la política de severidad.
107
+ - `summary-json`: resumen compacto para pasos posteriores.
108
+
109
+ ## Documentación
110
+
111
+ - [docs/checks.md](docs/checks.md)
112
+ - [docs/github-action.md](docs/github-action.md)
113
+ - [docs/roadmaps/roadmap2.md](docs/roadmaps/roadmap2.md)
@@ -0,0 +1,91 @@
1
+ # ManageProjectTool
2
+
3
+ ManageProjectTool audita repositorios con un engine Python, un coordinator
4
+ Node.js, una app Electron y una GitHub Action reutilizable para CI.
5
+
6
+ ## Capacidades actuales
7
+
8
+ - Ejecuta checks core y plugins sobre documentación, CI, dependencias y seguridad.
9
+ - Aplica severidades efectivas (`error`, `warning`, `info`) y umbrales como
10
+ `thresholds.maxWarnings` desde `mpt.config.json`.
11
+ - Expone un CLI standalone con `mpt scan` y `mpt init`.
12
+ - Genera reportes en JSON, HTML y Markdown según el flujo de uso.
13
+
14
+ ## Uso local
15
+
16
+ ### CLI Python
17
+
18
+ ```bash
19
+ python -m engine.cli scan .
20
+ python -m engine.cli scan . --format json
21
+ python -m engine.cli init .
22
+ ```
23
+
24
+ ### Validación del workspace
25
+
26
+ ```bash
27
+ npm install
28
+ npm run validate
29
+ ```
30
+
31
+ `npm run validate` ejecuta formato, linters y tests en secuencia.
32
+
33
+ ### Preparación de release (Fase B)
34
+
35
+ ```bash
36
+ npm run release:check
37
+ ```
38
+
39
+ Este comando valida prerequisitos implementables en el repo para `v0.1.0`
40
+ (`LICENSE`, artefactos de Action y assets de Electron) y lista pendientes
41
+ externos como Trusted Publisher en PyPI, `NPM_TOKEN` y Marketplace.
42
+
43
+ ## GitHub Action
44
+
45
+ La Action Docker definida en la raíz permite reutilizar el engine sin levantar
46
+ el coordinator.
47
+
48
+ ```yaml
49
+ name: Scan repository
50
+
51
+ on:
52
+ pull_request:
53
+ workflow_dispatch:
54
+
55
+ jobs:
56
+ scan:
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ - name: Run ManageProjectTool
61
+ id: mpt
62
+ uses: jaminsmoke/ManageProjectTool@v0.1.0
63
+ with:
64
+ target-path: .
65
+ format: markdown
66
+ checks: readme-presence,lockfile,ci-workflow-presence
67
+ - name: Upload report
68
+ if: always()
69
+ uses: actions/upload-artifact@v4
70
+ with:
71
+ name: mpt-report
72
+ path: ${{ steps.mpt.outputs.report-path }}
73
+ ```
74
+
75
+ Entradas soportadas:
76
+
77
+ - `target-path`: ruta relativa dentro de `GITHUB_WORKSPACE`.
78
+ - `checks`: lista separada por comas; vacía usa `mpt.config.json` o todos los checks.
79
+ - `format`: `markdown` o `json`.
80
+
81
+ Salidas expuestas:
82
+
83
+ - `report-path`: fichero generado en `reports/`.
84
+ - `exit-code`: resultado efectivo de la política de severidad.
85
+ - `summary-json`: resumen compacto para pasos posteriores.
86
+
87
+ ## Documentación
88
+
89
+ - [docs/checks.md](docs/checks.md)
90
+ - [docs/github-action.md](docs/github-action.md)
91
+ - [docs/roadmaps/roadmap2.md](docs/roadmaps/roadmap2.md)
@@ -0,0 +1,21 @@
1
+ # Documentación del proyecto ManageProjectTool
2
+
3
+ Este directorio contiene los documentos que definen el alcance, diseño y roadmap del proyecto.
4
+
5
+ Archivos:
6
+
7
+ - `vision.md` — Visión y objetivos
8
+ - `requirements.md` — Requisitos y alcance
9
+ - `architecture.md` — Arquitectura y decisiones
10
+ - `structure_conventions.md` — Estructura del repositorio y convenciones
11
+ - `metrics.md` — Métricas y reglas para auditoría automática
12
+ - `checks.md` — Catálogo de checks, severidades y política de salida
13
+ - `github-action.md` — Uso de la GitHub Action Docker y sus outputs
14
+ - `roadmaps/roadmap2.md` — Roadmap activo y milestones vigentes
15
+ - `contribution.md` — Guía para contribuir
16
+
17
+ Cómo usar:
18
+
19
+ - Completa y revisa cada documento.
20
+ - Los cambios en la carpeta `docs` deben discutirse en PRs.
21
+ - Próximo paso: cerrar los pendientes externos de la Fase B y validar el primer release público.
@@ -0,0 +1,10 @@
1
+ # Electron Assets
2
+
3
+ Esta carpeta contiene los iconos usados por `electron-builder`:
4
+
5
+ - `icon.ico` (Windows)
6
+ - `icon.icns` (macOS)
7
+ - `icon.png` (Linux)
8
+
9
+ Las referencias `icon:` ya están habilitadas en
10
+ [electron-builder.yml](../../electron-builder.yml).
@@ -0,0 +1 @@
1
+ """ManageProjectTool engine package."""
@@ -0,0 +1,49 @@
1
+ """A1 checks package — nuevos checks estándar del roadmap v2 Fase A."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from engine.checks import (
8
+ changelog_presence,
9
+ contributing_presence,
10
+ dependency_freshness,
11
+ env_example_presence,
12
+ gitignore_presence,
13
+ license_presence,
14
+ package_json_fields,
15
+ secrets_scan,
16
+ security_audit,
17
+ test_presence,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from engine.engine import CheckDefinition, CheckRunner
22
+
23
+ ALL_DEFINITIONS: list[CheckDefinition] = [
24
+ contributing_presence.DEFINITION,
25
+ changelog_presence.DEFINITION,
26
+ license_presence.DEFINITION,
27
+ env_example_presence.DEFINITION,
28
+ package_json_fields.DEFINITION,
29
+ gitignore_presence.DEFINITION,
30
+ dependency_freshness.DEFINITION,
31
+ test_presence.DEFINITION,
32
+ security_audit.DEFINITION,
33
+ secrets_scan.DEFINITION,
34
+ ]
35
+
36
+ ALL_RUNNERS: dict[str, CheckRunner] = {
37
+ contributing_presence.DEFINITION["id"]: contributing_presence.run,
38
+ changelog_presence.DEFINITION["id"]: changelog_presence.run,
39
+ license_presence.DEFINITION["id"]: license_presence.run,
40
+ env_example_presence.DEFINITION["id"]: env_example_presence.run,
41
+ package_json_fields.DEFINITION["id"]: package_json_fields.run,
42
+ gitignore_presence.DEFINITION["id"]: gitignore_presence.run,
43
+ dependency_freshness.DEFINITION["id"]: dependency_freshness.run,
44
+ test_presence.DEFINITION["id"]: test_presence.run,
45
+ security_audit.DEFINITION["id"]: security_audit.run,
46
+ secrets_scan.DEFINITION["id"]: secrets_scan.run,
47
+ }
48
+
49
+ __all__ = ["ALL_DEFINITIONS", "ALL_RUNNERS"]
@@ -0,0 +1,36 @@
1
+ """Check: changelog-presence — verifica que existe CHANGELOG.md o RELEASES.md."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from engine.engine import CheckDefinition, CheckResult
11
+
12
+ DEFINITION: CheckDefinition = {
13
+ "id": "changelog-presence",
14
+ "name": "CHANGELOG presente",
15
+ "category": "docs",
16
+ "severity": "medium",
17
+ }
18
+
19
+ _CANDIDATES = [
20
+ "CHANGELOG.md",
21
+ "CHANGELOG.rst",
22
+ "CHANGELOG.txt",
23
+ "CHANGELOG",
24
+ "RELEASES.md",
25
+ "RELEASES.rst",
26
+ "HISTORY.md",
27
+ "CHANGES.md",
28
+ "docs/CHANGELOG.md",
29
+ ]
30
+
31
+
32
+ def run(repo_path: str) -> CheckResult:
33
+ for candidate in _CANDIDATES:
34
+ if os.path.isfile(os.path.join(repo_path, candidate)):
35
+ return {"ok": True, "file": candidate, "candidates": _CANDIDATES}
36
+ return {"ok": False, "file": None, "candidates": _CANDIDATES}
@@ -0,0 +1,33 @@
1
+ """Check: contributing-presence — verifica que existe CONTRIBUTING.md."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from engine.engine import CheckDefinition, CheckResult
11
+
12
+ DEFINITION: CheckDefinition = {
13
+ "id": "contributing-presence",
14
+ "name": "CONTRIBUTING presente",
15
+ "category": "docs",
16
+ "severity": "medium",
17
+ }
18
+
19
+ _CANDIDATES = [
20
+ "CONTRIBUTING.md",
21
+ "CONTRIBUTING.rst",
22
+ "CONTRIBUTING.txt",
23
+ "CONTRIBUTING",
24
+ ".github/CONTRIBUTING.md",
25
+ "docs/CONTRIBUTING.md",
26
+ ]
27
+
28
+
29
+ def run(repo_path: str) -> CheckResult:
30
+ for candidate in _CANDIDATES:
31
+ if os.path.isfile(os.path.join(repo_path, candidate)):
32
+ return {"ok": True, "file": candidate, "candidates": _CANDIDATES}
33
+ return {"ok": False, "file": None, "candidates": _CANDIDATES}
@@ -0,0 +1,98 @@
1
+ """Check: dependency-freshness — detecta dependencias muy desactualizadas."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import subprocess
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from engine.engine import CheckDefinition, CheckResult
13
+
14
+ DEFINITION: CheckDefinition = {
15
+ "id": "dependency-freshness",
16
+ "name": "Dependencias actualizadas",
17
+ "category": "dependencies",
18
+ "severity": "medium",
19
+ }
20
+
21
+ _SUBPROCESS_TIMEOUT = 30
22
+
23
+
24
+ def _run_npm_outdated(repo_path: str) -> dict[str, object] | None:
25
+ """Run `npm outdated --json`. Returns parsed output or None if unavailable."""
26
+ pkg_path = os.path.join(repo_path, "package.json")
27
+ if not os.path.isfile(pkg_path):
28
+ return None
29
+ try:
30
+ proc = subprocess.run(
31
+ ["npm", "outdated", "--json"],
32
+ cwd=repo_path,
33
+ capture_output=True,
34
+ text=True,
35
+ timeout=_SUBPROCESS_TIMEOUT,
36
+ check=False,
37
+ )
38
+ if proc.stdout.strip():
39
+ return json.loads(proc.stdout)
40
+ return {}
41
+ except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
42
+ return None
43
+
44
+
45
+ def _run_pip_outdated(repo_path: str) -> list[dict[str, str]] | None:
46
+ """Run `pip list --outdated --format json`. Returns list or None if unavailable."""
47
+ has_reqs = any(
48
+ os.path.isfile(os.path.join(repo_path, f))
49
+ for f in (
50
+ "requirements.txt",
51
+ "pyproject.toml",
52
+ "Pipfile",
53
+ "setup.py",
54
+ "setup.cfg",
55
+ )
56
+ )
57
+ if not has_reqs:
58
+ return None
59
+ try:
60
+ proc = subprocess.run(
61
+ ["pip", "list", "--outdated", "--format", "json"],
62
+ cwd=repo_path,
63
+ capture_output=True,
64
+ text=True,
65
+ timeout=_SUBPROCESS_TIMEOUT,
66
+ check=False,
67
+ )
68
+ if proc.stdout.strip():
69
+ return json.loads(proc.stdout)
70
+ return []
71
+ except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
72
+ return None
73
+
74
+
75
+ def run(repo_path: str) -> CheckResult:
76
+ npm_outdated = _run_npm_outdated(repo_path)
77
+ pip_outdated = _run_pip_outdated(repo_path)
78
+
79
+ if npm_outdated is None and pip_outdated is None:
80
+ return {
81
+ "ok": True,
82
+ "skipped": True,
83
+ "reason": "No supported ecosystems detected or tools unavailable",
84
+ "npm_outdated": None,
85
+ "pip_outdated": None,
86
+ }
87
+
88
+ npm_count = len(npm_outdated) if npm_outdated else 0
89
+ pip_count = len(pip_outdated) if pip_outdated else 0
90
+ total_outdated = npm_count + pip_count
91
+
92
+ return {
93
+ "ok": total_outdated == 0,
94
+ "skipped": False,
95
+ "total_outdated": total_outdated,
96
+ "npm_outdated": npm_outdated,
97
+ "pip_outdated": pip_outdated,
98
+ }
@@ -0,0 +1,73 @@
1
+ """Check: env-example-presence — si hay referencias a .env en el repo, existe .env.example."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from engine.engine import CheckDefinition, CheckResult
11
+
12
+ DEFINITION: CheckDefinition = {
13
+ "id": "env-example-presence",
14
+ "name": ".env.example presente cuando se usan variables de entorno",
15
+ "category": "hygiene",
16
+ "severity": "high",
17
+ }
18
+
19
+ _ENV_INDICATORS = [
20
+ ".env",
21
+ "docker-compose.yml",
22
+ "docker-compose.yaml",
23
+ "docker-compose.override.yml",
24
+ ]
25
+
26
+ _DOCKER_COMPOSE_ENV_MARKER = ".env"
27
+
28
+
29
+ def _has_env_usage(repo_path: str) -> bool:
30
+ """Return True if the repo shows signs of relying on a .env file."""
31
+ if os.path.isfile(os.path.join(repo_path, ".env")):
32
+ return True
33
+
34
+ for compose_name in ("docker-compose.yml", "docker-compose.yaml"):
35
+ compose_path = os.path.join(repo_path, compose_name)
36
+ if not os.path.isfile(compose_path):
37
+ continue
38
+ try:
39
+ with open(compose_path, encoding="utf-8") as f:
40
+ if ".env" in f.read():
41
+ return True
42
+ except OSError:
43
+ pass
44
+
45
+ makefile_path = os.path.join(repo_path, "Makefile")
46
+ if os.path.isfile(makefile_path):
47
+ try:
48
+ with open(makefile_path, encoding="utf-8") as f:
49
+ if ".env" in f.read():
50
+ return True
51
+ except OSError:
52
+ pass
53
+
54
+ return False
55
+
56
+
57
+ def run(repo_path: str) -> CheckResult:
58
+ if not _has_env_usage(repo_path):
59
+ return {
60
+ "ok": True,
61
+ "skipped": True,
62
+ "reason": "No .env usage detected",
63
+ "file": None,
64
+ }
65
+
66
+ example_path = os.path.join(repo_path, ".env.example")
67
+ found = os.path.isfile(example_path)
68
+ return {
69
+ "ok": found,
70
+ "skipped": False,
71
+ "file": ".env.example" if found else None,
72
+ "has_env_usage": True,
73
+ }