Feat(ADN): Creado subcomando 'conocimiento' para asimilar documentación
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# tools/adn/comando/conocimiento.rb — Subcomando para gestionar la Base de Conocimiento del ADN
|
||||
# ==============================================================================
|
||||
# Inyecta nuevos documentos y los referencia automáticamente en el 00_indice.md
|
||||
# cumpliendo con el principio de Armonía Integral.
|
||||
|
||||
require 'optparse'
|
||||
require 'fileutils'
|
||||
require 'date'
|
||||
|
||||
module ADN
|
||||
class SubcomandoConocimiento
|
||||
def initialize(args, logger)
|
||||
@args = args
|
||||
@logger = logger
|
||||
@indice_path = File.join(PROJECT_ROOT, 'adn', '00_indice.md')
|
||||
@conocimiento_dir = File.join(PROJECT_ROOT, 'adn', 'conocimiento')
|
||||
end
|
||||
|
||||
def ejecutar
|
||||
if @args.empty? || @args[0] == 'help'
|
||||
mostrar_ayuda
|
||||
return
|
||||
end
|
||||
|
||||
subcomando = @args[0]
|
||||
sub_args = @args[1..-1] || []
|
||||
|
||||
case subcomando
|
||||
when 'asimilar'
|
||||
comando_asimilar(sub_args)
|
||||
else
|
||||
@logger.error("Subcomando desconocido: conocimiento #{subcomando}")
|
||||
puts "#{Color::RED}✗ Subcomando desconocido: '#{subcomando}'#{Color::RESET}"
|
||||
mostrar_ayuda
|
||||
exit 1
|
||||
end
|
||||
rescue Interrupt
|
||||
puts "\n#{Color::YELLOW}⚠ Operación interrumpida#{Color::RESET}"
|
||||
exit 130
|
||||
rescue StandardError => e
|
||||
@logger.error("Error asimilando conocimiento: #{e.message}")
|
||||
puts "#{Color::RED}✗ Error: #{e.message}#{Color::RESET}"
|
||||
puts "#{Color::DIM}#{e.backtrace.first}#{Color::RESET}" if ENV['ADN_DEBUG']
|
||||
exit 1
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def comando_asimilar(args)
|
||||
opts = { forzar: false }
|
||||
|
||||
parser = OptionParser.new do |opt|
|
||||
opt.banner = "Uso: adn conocimiento asimilar <archivo.md> [OPCIONES]"
|
||||
opt.on("-f", "--force", "Forzar sobrescritura si el documento ya está asimilado") do
|
||||
opts[:forzar] = true
|
||||
end
|
||||
opt.on("-h", "--help", "Mostrar ayuda") do
|
||||
puts opt
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
parser.parse!(args)
|
||||
rescue OptionParser::InvalidOption => e
|
||||
puts "#{Color::RED}✗ Error: #{e.message}#{Color::RESET}"
|
||||
puts parser
|
||||
exit 1
|
||||
end
|
||||
|
||||
archivo_origen = args[0]
|
||||
|
||||
if archivo_origen.nil? || archivo_origen.strip.empty?
|
||||
puts "#{Color::RED}✗ Se requiere la ruta de un archivo Markdown.#{Color::RESET}"
|
||||
puts parser
|
||||
exit 1
|
||||
end
|
||||
|
||||
unless File.exist?(archivo_origen)
|
||||
puts "#{Color::RED}✗ El archivo origen no existe: #{archivo_origen}#{Color::RESET}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts "#{Color::CYAN}🧠 Asimilando conocimiento desde #{archivo_origen}...#{Color::RESET}"
|
||||
|
||||
# Preparar el directorio de conocimiento
|
||||
FileUtils.mkdir_p(@conocimiento_dir) unless Dir.exist?(@conocimiento_dir)
|
||||
|
||||
nombre_base = File.basename(archivo_origen)
|
||||
archivo_destino = File.join(@conocimiento_dir, nombre_base)
|
||||
|
||||
if File.exist?(archivo_destino) && !opts[:forzar]
|
||||
puts "#{Color::YELLOW}⚠ El documento ya existe en la base de ADN. Usa --force para sobrescribir.#{Color::RESET}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Copiar el archivo
|
||||
FileUtils.cp(archivo_origen, archivo_destino)
|
||||
puts " #{Color::DIM}Documento integrado físicamente en: adn/conocimiento/#{nombre_base}#{Color::RESET}"
|
||||
|
||||
# Extraer metadatos
|
||||
contenido = File.read(archivo_destino)
|
||||
titulo = contenido.match(/^#\s+(.+)$/)&.captures&.first || nombre_base.sub('.md', '').capitalize
|
||||
|
||||
# Buscar el primer párrafo que no sea un título ni un bloque especial
|
||||
resumen = "Asimilación automatizada de módulo."
|
||||
parrafos = contenido.split("\n\n").reject { |p| p.start_with?('#', '>', '<', '---', '!') || p.strip.empty? }
|
||||
if parrafos.any?
|
||||
resumen_limpio = parrafos.first.gsub("\n", " ").strip
|
||||
resumen = resumen_limpio[0..147] + "..." if resumen_limpio.length > 150
|
||||
resumen = resumen_limpio if resumen_limpio.length <= 150
|
||||
end
|
||||
|
||||
# Actualizar 00_indice.md
|
||||
actualizar_indice(nombre_base, titulo, resumen)
|
||||
|
||||
puts "#{Color::GREEN}✅ Conocimiento asimilado correctamente y propagado a ADN/00_indice.md#{Color::RESET}"
|
||||
@logger.info("Conocimiento asimilado: #{nombre_base}")
|
||||
end
|
||||
|
||||
def actualizar_indice(nombre_archivo, titulo, resumen)
|
||||
contenido_indice = File.read(@indice_path)
|
||||
fecha_hoy = Date.today.strftime("%d/%m/%Y")
|
||||
ruta_relativa = "conocimiento/#{nombre_archivo}"
|
||||
|
||||
fila_markdown = "| [**#{titulo}**](#{ruta_relativa}) | #{fecha_hoy} | #{resumen} |"
|
||||
|
||||
# Comprobar si ya existe la sección de conocimiento
|
||||
seccion_conocimiento = "## 📚 Base de Conocimiento"
|
||||
|
||||
if contenido_indice.include?(seccion_conocimiento)
|
||||
# Revisión de duplicados
|
||||
return if contenido_indice.include?(ruta_relativa) && !contenido_indice.include?("Sobrescribir")
|
||||
|
||||
# Encontrar el final de la tabla e insertar la fila (reemplazando si hace falta actualizar)
|
||||
lineas = contenido_indice.lines
|
||||
idx_seccion = lineas.index { |l| l.include?(seccion_conocimiento) }
|
||||
|
||||
# Insertar después de las cabeceras de la tabla
|
||||
idx_insercion = idx_seccion + 4
|
||||
|
||||
lineas.insert(idx_insercion, "#{fila_markdown}\n")
|
||||
File.write(@indice_path, lineas.join)
|
||||
else
|
||||
# Inyectar toda la sección al final del archivo
|
||||
bloque_nuevo = <<~MD
|
||||
|
||||
---
|
||||
|
||||
#{seccion_conocimiento}
|
||||
|
||||
| Documento | Fecha de Asimilación | Descripción |
|
||||
| :--- | :--- | :--- |
|
||||
#{fila_markdown}
|
||||
|
||||
MD
|
||||
|
||||
File.open(@indice_path, 'a') do |f|
|
||||
f.puts bloque_nuevo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mostrar_ayuda
|
||||
puts "#{Color::CYAN}🧠 Herramienta ADN - Gestión de Base de Conocimiento#{Color::RESET}"
|
||||
puts "Permite inyectar, organizar e indexar nueva documentación en el motor autónomo."
|
||||
puts ""
|
||||
puts "#{Color::BOLD}SUBCOMANDOS:#{Color::RESET}"
|
||||
puts " #{Color::CYAN}asimilar <archivo.md>#{Color::RESET} Ingiere un documento Markdown a la base cognitiva del ADN."
|
||||
puts ""
|
||||
puts "#{Color::BOLD}EJEMPLOS:#{Color::RESET}"
|
||||
puts " ./tools/adn/run conocimiento asimilar docs/configuracion_bd.md"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user