[ADN] Fase 10: Saneamiento y Consolidación - Un solo punto de verdad
- S1: Eliminar 'triggers' duplicado en run (líneas 109/131) - S2: Eliminar cli/commit.rb (truncado, sin uso) - S3: Eliminar cli/inicio.rb y cli/cierre.rb (legacy, jornada.rb los reemplaza) - S4: Mover 4 planes obsoletos de docs/plan/adn/ a docs/_hist/plan/adn/ - S5: Mover 14 backups de planes y 3 docs técnicos a docs/_hist/ - S6: Eliminar manifiesto vacío P2604_proyecto_p2604.md - S7: Corregir referencia a plan obsoleto en run - S8: Dejar de cargar core/validador.rb obsoleto en run - S9: Limpiar progreso duplicado en P2604_mejoras_ADN.md - Agregar Fase 10 al plan P2604 con 10 tareas - Un solo punto de verdad: adn/README.md - Un solo plan: docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md - Registro en bitácora: evento 1073
This commit is contained in:
@@ -2,9 +2,12 @@
|
||||
|
||||
# adn/tools/core/constants.rb — Definición centralizada de rutas y constantes del ADN
|
||||
# ==============================================================================
|
||||
# Este módulo centraliza todas las constantes reutilizables del sistema ADN.
|
||||
# Following: Menos es Más (una fuente de verdad)
|
||||
|
||||
module ADN
|
||||
# El script 'run' está en adn/tools/run, por lo que la raíz es 2 niveles arriba
|
||||
# === RUTAS DEL PROYECTO ===
|
||||
|
||||
PROJECT_ROOT = File.expand_path('../../..', __dir__)
|
||||
|
||||
NODOS_DIR = File.join(PROJECT_ROOT, 'nodos')
|
||||
@@ -12,10 +15,46 @@ module ADN
|
||||
BITACORAS_DIR = File.join(PROJECT_ROOT, 'docs', 'bitacoras')
|
||||
LOGS_DIR = File.join(BITACORAS_DIR, '_hist')
|
||||
|
||||
# Directorios de herramientas
|
||||
TOOLS_DIR = File.join(PROJECT_ROOT, 'adn', 'tools')
|
||||
SEGURIDAD_DIR = File.join(TOOLS_DIR, 'seguridad')
|
||||
|
||||
# Bóveda
|
||||
CANDADOS_PATH = File.join(SEGURIDAD_DIR, 'ns8-candados.rb')
|
||||
|
||||
# === ESTADOS DE BITÁCORA ===
|
||||
|
||||
ESTADOS = {
|
||||
pendiente: '⏳',
|
||||
completado: '✅',
|
||||
fallido: '❌',
|
||||
advertencia: '⚠️',
|
||||
pausado: '⏸️',
|
||||
en_proceso: '📍'
|
||||
}.freeze
|
||||
|
||||
# === MODOS DE TRABAJO ===
|
||||
|
||||
MODOS = {
|
||||
presencial: 'P',
|
||||
remoto: 'R'
|
||||
}.freeze
|
||||
|
||||
# === CONFIGURACIÓN DE BASE DE DATOS ===
|
||||
|
||||
DB_CONFIG = {
|
||||
host: 'localhost',
|
||||
puerto: 5433,
|
||||
nombre: 'dtic_bitacoras',
|
||||
schema: 'bitacoras'
|
||||
}.freeze
|
||||
|
||||
# === EXCEPCIONES PERSONALIZADAS ===
|
||||
|
||||
class Error < StandardError; end
|
||||
class ConfigError < Error; end
|
||||
class DBError < Error; end
|
||||
class ValidationError < Error; end
|
||||
class NetworkError < Error; end
|
||||
|
||||
# === VERSIÓN ===
|
||||
|
||||
VERSION = '1.0.0'.freeze
|
||||
end
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# adn/tools/core/error_handler.rb — Helper para mensajes de error estandarizados
|
||||
# ==============================================================================
|
||||
# módulo reutilizable para formateo consistente de errores en CLI
|
||||
|
||||
module ADN
|
||||
module ErrorHandler
|
||||
module_function
|
||||
|
||||
def error(msg, code: 1)
|
||||
puts "#{Color::RED}✗ #{msg}#{Color::RESET}"
|
||||
exit(code)
|
||||
end
|
||||
|
||||
def warning(msg)
|
||||
puts "#{Color::YELLOW}⚠ #{msg}#{Color::RESET}"
|
||||
end
|
||||
|
||||
def info(msg)
|
||||
puts "#{Color::CYAN}ℹ #{msg}#{Color::RESET}"
|
||||
end
|
||||
|
||||
def success(msg)
|
||||
puts "#{Color::GREEN}✓ #{msg}#{Color::RESET}"
|
||||
end
|
||||
|
||||
def debug(msg)
|
||||
puts "#{Color::DIM}🔍 #{msg}#{Color::RESET}" if ENV['ADN_DEBUG']
|
||||
end
|
||||
|
||||
def die(msg, code: 1)
|
||||
error(msg, code: code)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# adn/tools/core/help_formatter.rb - Formateador de ayuda estandarizado
|
||||
# ======================================================================
|
||||
# Helper reutilizable para formateo consistente de --help en CLI
|
||||
|
||||
require_relative 'colores'
|
||||
|
||||
module ADN
|
||||
module HelpFormatter
|
||||
module_function
|
||||
|
||||
def format_header(titulo, descripcion = nil)
|
||||
lines = []
|
||||
lines << "#{Color::BOLD}#{titulo}#{Color::RESET}"
|
||||
lines << "#{Color::DIM}#{'=' * titulo.length}#{Color::RESET}" if descripcion
|
||||
lines << ""
|
||||
lines << "#{Color::CYAN}#{descripcion}#{Color::RESET}" if descripcion
|
||||
lines << ""
|
||||
lines.join("\n")
|
||||
end
|
||||
|
||||
def format_usage(comando, formato)
|
||||
"Uso: #{Color::YELLOW}#{comando}#{Color::RESET} #{formato}"
|
||||
end
|
||||
|
||||
def format_option(opciones, descripcion, default = nil)
|
||||
opt_str = opciones.map { |o| o.length > 1 ? "--#{o}" : "-#{o}" }.join(', ')
|
||||
default_str = default ? " (default: #{default})" : ""
|
||||
" #{Color::GREEN}#{opt_str.ljust(20)}#{Color::RESET} #{descripcion}#{default_str}"
|
||||
end
|
||||
|
||||
def format_example(comando, descripcion)
|
||||
"#{Color::DIM} $ #{comando}#{Color::RESET}\n #{Color::CYAN}#{descripcion}#{Color::RESET}"
|
||||
end
|
||||
|
||||
def format_section(titulo)
|
||||
"\n#{Color::BOLD}#{titulo}#{Color::RESET}\n"
|
||||
end
|
||||
|
||||
def generar_help(titulo:, descripcion:, uso:, opciones:, ejemplos: [])
|
||||
lines = []
|
||||
lines << format_header(titulo, descripcion)
|
||||
lines << uso
|
||||
lines << ""
|
||||
|
||||
if opciones.any?
|
||||
lines << format_section("Opciones:")
|
||||
opciones.each do |opt|
|
||||
lines << format_option(opt[:names], opt[:desc], opt[:default])
|
||||
end
|
||||
end
|
||||
|
||||
if ejemplos.any?
|
||||
lines << format_section("Ejemplos:")
|
||||
ejemplos.each do |ej|
|
||||
lines << format_example(ej[:cmd], ej[:desc])
|
||||
end
|
||||
end
|
||||
|
||||
lines.join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
+50
-13
@@ -4,7 +4,7 @@
|
||||
# ====================================================================
|
||||
# Este módulo proporciona logging estructurado en JSON para todas las
|
||||
# herramientas del sistema ADN. Los logs se almacenan en `logs/adn/`
|
||||
# con rotación diaria automática.
|
||||
# con rotación diaria automática y por tamaño.
|
||||
|
||||
require 'json'
|
||||
require 'fileutils'
|
||||
@@ -13,32 +13,30 @@ require 'time'
|
||||
|
||||
module ADN
|
||||
class Logger
|
||||
# Niveles de log soportados
|
||||
NIVELES = %w[DEBUG INFO EXITO ADVERTENCIA ERROR].freeze
|
||||
|
||||
# Configuración de rotación
|
||||
MAX_TAMANO_MB = 10
|
||||
MAX_ARCHIVOS = 7
|
||||
|
||||
require_relative 'colores'
|
||||
|
||||
# Inicializa el logger
|
||||
#
|
||||
# @param opts [Hash] Opciones de configuración
|
||||
# @option opts [String] :directorio Directorio para logs (default: logs/adn/)
|
||||
# @option opts [Boolean] :terminal Mostrar logs en terminal (default: true)
|
||||
# @option opts [Boolean] :colores Usar colores en terminal (default: true)
|
||||
# @option opts [String] :archivo Nombre base del archivo de log (default: fecha actual)
|
||||
def initialize(opts = {})
|
||||
@directorio = opts[:directorio] || File.join(File.expand_path('../../..', __dir__), 'logs', 'adn')
|
||||
@mostrar_terminal = opts.fetch(:terminal, true)
|
||||
@usar_colores = opts.fetch(:colores, true)
|
||||
@archivo_base = opts[:archivo] || Date.today.iso8601
|
||||
|
||||
# Nivel mínimo de log (configurable)
|
||||
@nivel_minimo = opts[:nivel] || 'DEBUG'
|
||||
|
||||
# Crear directorio si no existe
|
||||
FileUtils.mkdir_p(@directorio) unless Dir.exist?(@directorio)
|
||||
|
||||
# Ruta completa del archivo de log
|
||||
@ruta_log = File.join(@directorio, "#{@archivo_base}.log")
|
||||
|
||||
# Buffer para logs (útil para pruebas o modo batch)
|
||||
@buffer = []
|
||||
|
||||
# Verificar rotación al iniciar
|
||||
verificar_rotacion
|
||||
end
|
||||
|
||||
# Registra un mensaje de nivel DEBUG
|
||||
@@ -209,6 +207,45 @@ module ADN
|
||||
|
||||
'adn.desconocido'
|
||||
end
|
||||
|
||||
# Verifica y ejecuta rotación de logs si es necesario
|
||||
def verificar_rotacion
|
||||
return unless File.exist?(@ruta_log)
|
||||
|
||||
tamano_mb = File.size(@ruta_log) / (1024.0 * 1024.0)
|
||||
|
||||
if tamano_mb > MAX_TAMANO_MB
|
||||
rotar_por_tamano
|
||||
end
|
||||
end
|
||||
|
||||
# Rota el log por tamaño (archivo muy grande)
|
||||
def rotar_por_tamano
|
||||
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
||||
archivo_rotado = "#{@ruta_log}.#{timestamp}"
|
||||
|
||||
FileUtils.mv(@ruta_log, archivo_rotado)
|
||||
limpiar_logs_antiguos
|
||||
|
||||
puts "#{Color::YELLOW}⚠ Log rotado por tamaño: #{archivo_rotado}#{Color::RESET}"
|
||||
end
|
||||
|
||||
# Limpia logs antiguos (más de MAX_ARCHIVOS)
|
||||
def limpiar_logs_antiguos
|
||||
patron = File.join(@directorio, '*.log.*')
|
||||
archivos = Dir.glob(patron).sort_by { |f| File.mtime(f) }
|
||||
|
||||
archivos[0...-MAX_ARCHIVOS].each do |archivo|
|
||||
File.delete(archivo) if File.exist?(archivo)
|
||||
end
|
||||
end
|
||||
|
||||
# Verifica si el nivel está habilitado
|
||||
def nivel_habilitado?(nivel)
|
||||
idx_actual = NIVELES.index(@nivel_minimo) || 0
|
||||
idx_nivel = NIVELES.index(nivel) || 0
|
||||
idx_nivel >= idx_actual
|
||||
end
|
||||
end
|
||||
|
||||
# Logger global preconfigurado para uso rápido
|
||||
|
||||
Reference in New Issue
Block a user