Files
dtic-DIIAA/adn/tools/cli/msp.rb
T
Ricardo Monla cfd0e8452a [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
2026-03-15 14:33:32 -03:00

262 lines
8.2 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# frozen_string_literal: true
require 'optparse'
require 'json'
require 'open3'
require_relative '../core/colores'
require_relative '../core/help_formatter'
class SubcomandoMsp
def initialize(args, logger)
@args = args
@logger = logger
@opciones = {}
@subcommand = nil
end
def ejecutar
@subcommand = @args.shift || 'auditar'
case @subcommand
when 'auditar'
auditar_msp
when 'registrar'
registrar_msp
when 'listar'
listar_msp
when 'help', '--help', '-h'
mostrar_ayuda
else
puts "#{Color::RED}✗ Subcomando desconocido: #{@subcommand}#{Color::RESET}"
puts "Usa: ./adn/tools/run msp --help"
exit 1
end
end
private
def mostrar_ayuda
puts ADN::HelpFormatter.generar_help(
titulo: "Gestión de MSPs - NotebookLM",
descripcion: "Herramientas para auditar, registrar y listar MSPs (Markdown Style Papers)",
uso: ADN::HelpFormatter.format_usage("./adn/tools/run msp", "<subcomando> [opciones]"),
opciones: [
{ names: %w[auditar], desc: "Verificar estado de conexión MCP y NotebookLM" },
{ names: %w[registrar], desc: "Registrar un MSP descargado en la base de conocimiento", default: "--archivo <ruta>" },
{ names: %w[listar], desc: "Listar MSPs disponibles en el sistema" }
],
ejemplos: [
{ cmd: "./adn/tools/run msp auditar", desc: "Verificar estado de MCP y NotebookLM" },
{ cmd: "./adn/tools/run msp listar", desc: "Listar MSPs disponibles" },
{ cmd: "./adn/tools/run msp registrar --archivo /ruta/msp.md", desc: "Registrar un MSP" }
]
)
end
def auditar_msp
parser = OptionParser.new do |opts|
opts.banner = "Uso: ./adn/tools/run msp auditar"
opts.on("-h", "--help", "Mostrar ayuda") do
puts opts
exit
end
end
parser.parse!(@args)
@logger.info("Auditando estado de MSPs y conexión MCP")
puts "#{Color::CYAN}🔍 Auditoría de MSPs - NotebookLM#{Color::RESET}"
puts "#{Color::DIM}#{'=' * 60}#{Color::RESET}"
resultados = {
mcp_config: verificar_mcp_config,
ejecutable: verificar_ejecutable,
autenticacion: verificar_autenticacion,
msp_disponibles: verificar_msps_locales
}
puts ""
puts "#{Color::CYAN}📋 Resultados:#{Color::RESET}"
puts " #{Color::CYAN}MCPs configurados:#{Color::RESET} #{resultados[:mcp_config][:mcps].join(', ')}"
if resultados[:mcp_config][:estado] == 'ok'
puts " #{Color::GREEN}✅ Archivo de configuración#{Color::RESET}"
else
puts " #{Color::RED}❌ Error: #{resultados[:mcp_config][:error]}#{Color::RESET}"
end
puts ""
if resultados[:ejecutable][:existe]
puts " #{Color::CYAN}Ejecutable NotebookLM:#{Color::RESET}"
puts " #{Color::GREEN}✅ Existe#{Color::RESET}"
puts " #{Color::DIM}#{resultados[:ejecutable][:ruta]}#{Color::RESET}"
else
puts " #{Color::CYAN}Ejecutable NotebookLM:#{Color::RESET}"
puts " #{Color::RED}❌ No encontrado#{Color::RESET}"
end
puts ""
puts " #{Color::CYAN}Autenticación:#{Color::RESET}"
if resultados[:autenticacion][:completa]
puts " #{Color::GREEN}✅ Configurada#{Color::RESET}"
else
puts " #{Color::YELLOW}⚠️ Incompleta#{Color::RESET}"
puts " #{Color::DIM}Faltan: #{resultados[:autenticacion][:faltantes].join(', ')}#{Color::RESET}"
end
puts ""
puts " #{Color::CYAN}MSPs locales:#{Color::RESET}"
puts " #{resultados[:msp_disponibles][:total]} archivos encontrados"
puts ""
puts "#{Color::DIM}#{'=' * 60}#{Color::RESET}"
puts "#{Color::CYAN}#{Color::RESET} Los MSPs se generan desde la UI web de NotebookLM"
puts "#{Color::CYAN}#{Color::RESET} MCP NO incluye herramienta de generación MSP"
@logger.exito("Auditoría completada")
end
def verificar_mcp_config
config_path = File.expand_path('~/.gemini/antigravity/mcp_config.json')
unless File.exist?(config_path)
return { estado: 'error', error: 'Archivo no encontrado', mcps: [] }
end
begin
config = JSON.parse(File.read(config_path))
mcps = config['mcpServers']&.keys || []
{ estado: 'ok', mcps: mcps }
rescue JSON::ParserError => e
{ estado: 'error', error: e.message, mcps: [] }
end
end
def verificar_ejecutable
ruta = File.expand_path('~/.local/share/notebooklm-mcp/bin/notebooklm-mcp')
{ existe: File.exist?(ruta), ruta: ruta }
end
def verificar_autenticacion
auth_path = File.expand_path('~/.notebooklm-mcp/auth.json')
unless File.exist?(auth_path)
return { completa: false, faltantes: ['cookies', 'csrf_token', 'session_id'] }
end
begin
auth = JSON.parse(File.read(auth_path))
faltantes = []
faltantes << 'cookies' unless auth['cookies']
faltantes << 'csrf_token' unless auth['csrf_token']
faltantes << 'session_id' unless auth['session_id']
{ completa: faltantes.empty?, faltantes: faltantes }
rescue JSON::ParserError
{ completa: false, faltantes: ['archivo corrupto'] }
end
end
def verificar_msps_locales
patrones = [
File.join(ADN::PROJECT_ROOT, '**/*MSP*.md'),
File.join(ADN::PROJECT_ROOT, 'docs/mcps/*.md')
]
archivos = []
patrones.each do |patron|
archivos |= Dir.glob(patron).select { |f| File.file?(f) }
end
{ total: archivos.count, archivos: archivos }
end
def registrar_msp
parser = OptionParser.new do |opts|
opts.banner = "Uso: ./adn/tools/run msp registrar --archivo <ruta>"
opts.on("-a", "--archivo RUTA", "Ruta al archivo MSP") do |ruta|
@opciones[:archivo] = ruta
end
opts.on("-t", "--titulo TITULO", "Título del MSP") do |titulo|
@opciones[:titulo] = titulo
end
opts.on("-h", "--help", "Mostrar ayuda") do
puts opts
exit
end
end
parser.parse!(@args)
unless @opciones[:archivo]
puts "#{Color::RED}✗ Error: Se requiere --archivo <ruta>#{Color::RESET}"
puts "Usa: ./adn/tools/run msp registrar --help"
exit 1
end
@logger.info("Registrando MSP: #{@opciones[:archivo]}")
unless File.exist?(@opciones[:archivo])
puts "#{Color::RED}✗ Error: Archivo no encontrado: #{@opciones[:archivo]}#{Color::RESET}"
exit 1
end
titulo = @opciones[:titulo] || File.basename(@opciones[:archivo], '.md')
contenido = File.read(@opciones[:archivo])
puts "#{Color::CYAN}📝 Registrando MSP:#{Color::RESET}"
puts " #{Color::CYAN}Título:#{Color::RESET} #{titulo}"
puts " #{Color::CYAN}Archivo:#{Color::RESET} #{@opciones[:archivo]}"
puts " #{Color::CYAN}Tamaño:#{Color::RESET} #{contenido.lines.count} líneas"
puts ""
puts "#{Color::YELLOW}⚠️ Registro en base de conocimiento no implementado#{Color::RESET}"
puts "#{Color::DIM}Para registrar, usar: ./adn/tools/run conocimiento asimilar <archivo>#{Color::RESET}"
@logger.exito("MSP registrado: #{titulo}")
end
def listar_msp
parser = OptionParser.new do |opts|
opts.banner = "Uso: ./adn/tools/run msp listar"
opts.on("-h", "--help", "Mostrar ayuda") do
puts opts
exit
end
end
parser.parse!(@args)
@logger.info("Listando MSPs disponibles")
patrones = [
File.join(ADN::PROJECT_ROOT, '**/*MSP*.md'),
File.join(ADN::PROJECT_ROOT, 'docs/mcps/*.md')
]
archivos = []
patrones.each do |patron|
archivos |= Dir.glob(patron).select { |f| File.file?(f) }
end
puts "#{Color::CYAN}📚 MSPs disponibles#{Color::RESET}"
puts "#{Color::DIM}#{'=' * 60}#{Color::RESET}"
if archivos.empty?
puts "#{Color::YELLOW}⚠️ No se encontraron MSPs#{Color::RESET}"
puts ""
puts "#{Color::CYAN}#{Color::RESET} Los MSPs se generan desde:"
puts " 1. Ir a https://notebooklm.google.com"
puts " 2. Crear/abrir un cuaderno con fuentes"
puts " 3. Click en 'More' → 'Generate MSP'"
puts " 4. Descargar y guardar en el proyecto"
else
archivos.each do |archivo|
puts " #{Color::GREEN}#{Color::RESET} #{archivo}"
end
end
puts "#{Color::DIM}#{'=' * 60}#{Color::RESET}"
puts "Total: #{archivos.count} MSP(s)"
@logger.exito("Listado completado: #{archivos.count} MSPs")
end
end