- 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
190 lines
7.3 KiB
Ruby
Executable File
190 lines
7.3 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
ENV['TZ'] = 'America/Argentina/Buenos_Aires'
|
|
|
|
# tools/adn.rb — Interfaz de línea de comandos unificada para el sistema ADN
|
|
# ============================================================================
|
|
# 🤖 DIRECTIVA IA: Esta herramienta es el punto de entrada principal para la
|
|
# automatización del ADN. Su objetivo es reducir progresivamente la dependencia
|
|
# de la IA mediante scripts Ruby autónomos.
|
|
# ============================================================================
|
|
# Uso: ./adn/tools/run <subcomando> [opciones] [argumentos]
|
|
#
|
|
# Subcomandos disponibles:
|
|
# validador [--watch] [--fix] Validar cumplimiento del ADN en bitácoras
|
|
# contexto <nodo> [--cmd] Obtener contexto topológico de un nodo
|
|
# nodos <acción> [opciones] Gestión de nodos (agrupar, listar, buscar)
|
|
# jornada <acción> [modo] [hora] Gestión de jornada (iniciar, cerrar, estado)
|
|
# salud [--dashboard] [--json] Ver salud general del sistema ADN
|
|
# generar bitacora [fecha] Generar nueva bitácora (fecha: YYYY-MM-DD)
|
|
# generar nodo <nombre> Generar ficha de nodo
|
|
# generar proyecto <código> Generar manifiesto de proyecto
|
|
# tailscale <acción> [opciones] Gestión de identidades Tailscale
|
|
# conocimiento asimilar <archivo> Asimilar documentación al ADN
|
|
# evolucion <propuesta.md> Gestionar propuesta de evolución del ADN
|
|
# msp <subcomando> Gestión de MSPs (auditar, registrar, listar)
|
|
# ayuda [subcomando] Mostrar ayuda detallada
|
|
#
|
|
# Documentación completa: docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md
|
|
|
|
require 'optparse'
|
|
require 'json'
|
|
require 'fileutils'
|
|
require 'date'
|
|
require 'time'
|
|
|
|
require_relative 'core/constants'
|
|
|
|
module ADN
|
|
# Aseguramos que los directorios existan
|
|
FileUtils.mkdir_p(LOGS_DIR) unless Dir.exist?(LOGS_DIR)
|
|
FileUtils.mkdir_p(BITACORAS_DIR) unless Dir.exist?(BITACORAS_DIR)
|
|
end
|
|
|
|
require_relative 'core/logger'
|
|
require_relative 'core/eventos'
|
|
require_relative 'core/triggers'
|
|
require_relative 'cli/db'
|
|
require_relative 'cli/plan'
|
|
require_relative 'cli/backup'
|
|
require_relative 'cli/triggers'
|
|
require_relative 'cli/conocimiento'
|
|
require_relative 'cli/jornada'
|
|
require_relative 'cli/proceso'
|
|
require_relative 'cli/estados'
|
|
require_relative 'cli/tailscale'
|
|
require_relative 'core/conciliador'
|
|
|
|
require_relative 'core/colores'
|
|
|
|
# ─── Logger estructurado ─────────────────────────────────────────────────
|
|
# El logger está implementado en adn/logger.rb
|
|
ADNLogger = ADN::Logger
|
|
|
|
require_relative 'cli/validador'
|
|
require_relative 'cli/contexto'
|
|
require_relative 'cli/generar'
|
|
require_relative 'cli/salud'
|
|
require_relative 'cli/ayuda'
|
|
require_relative 'cli/nodos'
|
|
require_relative 'cli/msp'
|
|
|
|
# ─── CLI Principal ──────────────────────────────────────────────────────
|
|
class ADNCLI
|
|
def initialize
|
|
@logger = ADNLogger.new
|
|
end
|
|
|
|
def ejecutar
|
|
if ARGV.empty?
|
|
SubcomandoAyuda.new([], @logger).ejecutar
|
|
exit 0
|
|
end
|
|
|
|
subcomando = ARGV[0]
|
|
|
|
# Saneamiento preventivo de pendientes (con cooldown de 5 minutos para performance)
|
|
ejecutar_saneamiento_preventivo(subcomando)
|
|
|
|
args = ARGV[1..-1] || []
|
|
|
|
case subcomando
|
|
when 'validador'
|
|
SubcomandoValidador.new(args, @logger).ejecutar
|
|
when 'contexto'
|
|
SubcomandoContexto.new(args, @logger).ejecutar
|
|
when 'salud'
|
|
SubcomandoSalud.new(args, @logger).ejecutar
|
|
when 'generar'
|
|
SubcomandoGenerar.new(args, @logger).ejecutar
|
|
when 'nodos'
|
|
ADN::SubcomandoNodos.new(args, @logger).ejecutar
|
|
when 'conocimiento'
|
|
ADN::SubcomandoConocimiento.new(args, @logger).ejecutar
|
|
when 'db'
|
|
ADN::SubcomandoDB.new(args, @logger).ejecutar
|
|
when 'backup', 'backups'
|
|
ADN::SubcomandoBackup.new(args, @logger).ejecutar
|
|
when 'triggers'
|
|
ADN::SubcomandoTriggers.new(args, @logger).ejecutar
|
|
when 'jornada'
|
|
ADN::SubcomandoJornada.new(args, @logger).ejecutar
|
|
when 'proceso'
|
|
ADN::SubcomandoProceso.new(args, @logger).ejecutar
|
|
when 'estados'
|
|
ADN::SubcomandoEstados.new(args, @logger).ejecutar
|
|
when 'tailscale', 'ts'
|
|
ADN::SubcomandoTailscale.new(args, @logger).ejecutar
|
|
when 'inicio'
|
|
# Compatibilidad: redirigir a jornada iniciar
|
|
ADN::SubcomandoJornada.new(['iniciar'] + args, @logger).ejecutar
|
|
when 'cierre'
|
|
# Compatibilidad: redirigir a jornada cerrar
|
|
ADN::SubcomandoJornada.new(['cerrar'] + args, @logger).ejecutar
|
|
when 'ayuda', 'help', '-h', '--help'
|
|
SubcomandoAyuda.new(args, @logger).ejecutar
|
|
when 'evolucion'
|
|
@logger.info("Subcomando 'evolucion' será implementado en Fase 2")
|
|
puts "#{Color::YELLOW}⚠ El subcomando 'evolucion' será implementado en Fase 2#{Color::RESET}"
|
|
puts " Ver plan: docs/plan/260307-1400_Plan_Mejoras_ADN.md"
|
|
when 'plan'
|
|
ADN::SubcomandoPlan.new(args, @logger).ejecutar
|
|
when 'msp'
|
|
SubcomandoMsp.new(args, @logger).ejecutar
|
|
else
|
|
@logger.error("Subcomando desconocido: #{subcomando}")
|
|
puts "#{Color::RED}✗ Subcomando desconocido: '#{subcomando}'#{Color::RESET}"
|
|
puts ""
|
|
SubcomandoAyuda.new([], @logger).ejecutar
|
|
exit 1
|
|
end
|
|
rescue Interrupt
|
|
puts "\n#{Color::YELLOW}⚠ Interrumpido por el usuario#{Color::RESET}"
|
|
@logger.info("Ejecución interrumpida por usuario")
|
|
exit 130
|
|
rescue OptionParser::InvalidOption => e
|
|
@logger.error("Opción inválida: #{e.message}")
|
|
puts "#{Color::RED}✗ Error: opción inválida #{e.message}#{Color::RESET}"
|
|
puts "Usa './adn/tools/run ayuda' para ver las opciones disponibles"
|
|
exit 1
|
|
rescue ADN::Error => e
|
|
@logger.error("Error de aplicación: #{e.message}")
|
|
puts "#{Color::RED}✗ #{e.message}#{Color::RESET}"
|
|
exit 1
|
|
rescue => e
|
|
@logger.error("Error inesperado: #{e.message}", { backtrace: e.backtrace })
|
|
puts "#{Color::RED}✗ Error inesperado: #{e.message}#{Color::RESET}"
|
|
puts "#{Color::DIM}#{e.backtrace.first(3).join("\n")}#{Color::RESET}" if ENV['ADN_DEBUG']
|
|
puts "\n#{Color::YELLOW}💡 Ejecuta con ADN_DEBUG=1 para ver el trace completo#{Color::RESET}"
|
|
exit 1
|
|
end
|
|
private
|
|
|
|
def ejecutar_saneamiento_preventivo(subcomando)
|
|
# No sanear si es ayuda o db (para evitar bucles o lentitud en info rápida)
|
|
return if ['ayuda', 'help', 'db', 'salud', '-h', '--help'].include?(subcomando)
|
|
|
|
archivo_cooldown = "/tmp/adn_sanity_cooldown"
|
|
cooldown_segundo = 300 # 5 minutos
|
|
|
|
if File.exist?(archivo_cooldown)
|
|
last_run = File.mtime(archivo_cooldown)
|
|
return if (Time.now - last_run) < cooldown_segundo
|
|
end
|
|
|
|
# Ejecutar conciliación
|
|
begin
|
|
# Tocamos el archivo primero para evitar que otras instancias concurrentes lo lancen
|
|
FileUtils.touch(archivo_cooldown)
|
|
ADN::Conciliador.new(@logger).ejecutar(silencioso: true)
|
|
rescue => e
|
|
@logger.advertencia("No se pudo completar el saneamiento preventivo: #{e.message}")
|
|
end
|
|
end
|
|
end
|
|
|
|
# ─── Punto de entrada ───────────────────────────────────────────────────
|
|
if __FILE__ == $0
|
|
ADNCLI.new.ejecutar
|
|
end
|