Architettura CLI
La CLI è organizzata come un package (src/zenzic/cli/) invece di un singolo modulo.
Ogni file gestisce un dominio di responsabilità.
Mappa dei Moduli
| Modulo | Responsabilità |
|---|---|
_shared.py | Singleton console, singleton _ui, configure_console() e tutte le utility cross-comando (_build_exclusion_manager, _output_json_findings, _render_link_error, ecc.) |
_check.py | Sub-app Typer check_app + sette comandi check *; helper privati re-esportati da _governance.py, _target_resolver.py e _command_setup.py |
_command_setup.py | Factory setup_command() — consolida la scoperta del repo root, il caricamento config, la risoluzione del target e la costruzione dell'exclusion manager usati da tutti i comandi check |
_clean.py | Sub-app Typer clean_app + comando clean assets |
_config_explain.py | Comando explain + surface di introspezione della genealogia config e delle regole |
_governance.py | Sub-app Typer config_app + comandi del profilo di governance + helper per i filtri per-file-ignore e directory-policy (_apply_per_file_ignores, _apply_directory_policies) |
_guard.py | Sub-app Typer guard_app + comandi scan / init per il fast secret guard |
_inspect.py | Sub-app Typer inspect_app + comandi capabilities, codes e routes |
_lab.py | Comando lab + showcase interattivo di scenari |
_metadata.py | Single source of truth per i pannelli help root, il raggruppamento dei comandi e il testo di short help |
_standalone.py | Comandi score, diff e init + i loro helper privati |
_target_resolver.py | _resolve_target() e _apply_target() — helper per la ricerca del path e il patching della config, condivisi dai comandi check e dal comando lab |
__init__.py | Surface di re-export pubblica consumata da main.py — non aggiungere logica qui |
main.py è la factory di registrazione Typer unificata. I nuovi comandi top-level e le sub-app
devono essere registrati lì, e i metadati dell'help root devono rimanere allineati con _metadata.py.
Il Visual State Manager
_shared.py è il solo proprietario di tutto lo stato della console e UI. Questa è la regola
architetturale più critica nel layer CLI:
DIVIETO: Nessun modulo comando può istanziare
Console()o una classe UI custom direttamente. Tutto l'output deve passare attraversoget_ui()eget_console()da_shared.py.
# ✅ Corretto — in qualsiasi modulo _check.py / _clean.py / _standalone.py
from . import _shared
_shared.get_ui().print_header(__version__)
_shared.get_console().print("output")
# ❌ VIETATO — non farlo mai in un modulo comando
from rich.console import Console
from mypackage.ui import LegacyInterfaceV1
console = Console(...) # rompe lo stato condiviso
ui = LegacyInterfaceV1(console) # crea un'istanza orfana
Per il razionale di design dietro la condivisione dello stato dell'interfaccia utente, vedere ADR 004 — Stato della Console Unificato.
Convenzioni output UI:
- Usa sempre
ZenzicPalette.DIMper testo dim/secondario — mai il tag Rich raw[dim]. - Spaziatura verticale: compatta (stile Ruff). Nessuna riga vuota tra le singole righe del footer.
Usa i separatori
Rule()solo per dividere le sezioni principali del report. - I nuovi simboli devono essere aggiunti a
_EMOJIinzenzic/core/ui.pyprima dell'uso — mai Unicode literal inline.
Aggiungere Comandi CLI
Per istruzioni passo-passo su come aggiungere comandi o nuove sub-app alla CLI, vedere Scrivere un Nuovo Check — Cablaggio CLI.
Codici di Uscita
La CLI termina con uno di quattro codici. Questi sono frozen — non aggiungere nuovi codici di uscita senza una decisione architetturale esplicita:
| Codice | Significato |
|---|---|
0 | Tutti i check superati |
1 | Problemi di qualità trovati |
2 | SECURITY — credenziale esposta rilevata |
3 | SECURITY — traversal del path di sistema rilevato |
PLUGIN_FORBIDDEN_EXITS garantisce che gli adapter di terze parti non possano emettere codici
di uscita al di fuori di questo insieme. Vedi il riferimento Adapter API per
il contratto completo.