From cfd0e8452a8ba8c45bfc9dc526922f1d0a9d8d03 Mon Sep 17 00:00:00 2001 From: Ricardo Monla Date: Sun, 15 Mar 2026 14:33:32 -0300 Subject: [PATCH] =?UTF-8?q?[ADN]=20Fase=2010:=20Saneamiento=20y=20Consolid?= =?UTF-8?q?aci=C3=B3n=20-=20Un=20solo=20punto=20de=20verdad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .github/workflows/lint.yml | 29 ++ .github/workflows/test.yml | 36 +++ adn/README.md | 22 +- adn/tools/.bundle/config | 2 +- adn/tools/.rubocop.yml | 17 ++ adn/tools/cli/ayuda.rb | 17 ++ adn/tools/cli/cierre.rb | 58 ---- adn/tools/cli/commit.rb | 9 - adn/tools/cli/contexto.rb | 77 ++---- adn/tools/cli/inicio.rb | 61 ---- adn/tools/cli/msp.rb | 261 ++++++++++++++++++ adn/tools/cli/nodos.rb | 38 +-- adn/tools/cli/validador.rb | 4 + adn/tools/core/constants.rb | 47 +++- adn/tools/core/error_handler.rb | 36 +++ adn/tools/core/help_formatter.rb | 64 +++++ adn/tools/core/logger.rb | 63 ++++- adn/tools/db/exporters/md_exporter.rb | 4 + adn/tools/run | 21 +- adn/tools/spec/core/colores_spec.rb | 33 +++ adn/tools/spec/core/validador_spec.rb | 40 +++ adn/tools/spec/db/evento_spec.rb | 41 +++ adn/tools/spec/spec_helper.rb | 11 + .../plan/adn/260307-0806_ArquitecturaADN.md | 0 .../plan/adn/260307-1400_Plan_Mejoras_ADN.md | 0 ..._Sugerencias_Mejoras_ADN_Automatizacion.md | 0 ...260308-1200_Plan_Integral_ADN_BITACORAs.md | 0 .../prompts}/mejora_README.md | 0 docs/_hist/tecnica/adn_cli.md | 105 +++++++ docs/_hist/tecnica/adn_core.md | 124 +++++++++ docs/_hist/tecnica/adn_tests.md | 83 ++++++ docs/mcps/MSPs-ADN.md | 73 +++++ docs/mcps/MSPs-Antigravity.md | 218 +++++++++++++++ docs/prompt/260313-1813_Pido_Usar_w-zombi.md | 2 +- .../260315-0917_Pido_Seguir_Con_P2604.md | 5 + .../p2604_mejoras_ADN/P2604_mejoras_ADN.md | 200 ++++++++++++++ 36 files changed, 1563 insertions(+), 238 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test.yml create mode 100644 adn/tools/.rubocop.yml delete mode 100644 adn/tools/cli/cierre.rb delete mode 100644 adn/tools/cli/commit.rb delete mode 100644 adn/tools/cli/inicio.rb create mode 100644 adn/tools/cli/msp.rb create mode 100644 adn/tools/core/error_handler.rb create mode 100644 adn/tools/core/help_formatter.rb create mode 100644 adn/tools/spec/core/colores_spec.rb create mode 100644 adn/tools/spec/core/validador_spec.rb create mode 100644 adn/tools/spec/db/evento_spec.rb create mode 100644 adn/tools/spec/spec_helper.rb rename docs/{ => _hist}/plan/adn/260307-0806_ArquitecturaADN.md (100%) rename docs/{ => _hist}/plan/adn/260307-1400_Plan_Mejoras_ADN.md (100%) rename docs/{ => _hist}/plan/adn/260307-1430_Sugerencias_Mejoras_ADN_Automatizacion.md (100%) rename docs/{ => _hist}/plan/adn/260308-1200_Plan_Integral_ADN_BITACORAs.md (100%) rename docs/{prompt => _hist/prompts}/mejora_README.md (100%) create mode 100644 docs/_hist/tecnica/adn_cli.md create mode 100644 docs/_hist/tecnica/adn_core.md create mode 100644 docs/_hist/tecnica/adn_tests.md create mode 100644 docs/mcps/MSPs-ADN.md create mode 100644 docs/mcps/MSPs-Antigravity.md create mode 100644 docs/prompt/260315-0917_Pido_Seguir_Con_P2604.md create mode 100644 docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..dc2444f6 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,29 @@ +name: Lint ADN + +on: + push: + paths: + - 'adn/tools/**/*.rb' + pull_request: + paths: + - 'adn/tools/**/*.rb' + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1' + + - name: Install RuboCop + run: gem install rubocop --no-document + + - name: Run RuboCop + run: | + cd adn/tools + rubocop --force-exclusion --config .rubocop.yml || true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..1ff314ff --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,36 @@ +name: Tests ADN + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1' + bundler-cache: true + + - name: Install dependencies + run: | + cd adn/tools + bundle install + + - name: Run tests + run: | + cd adn/tools + bundle exec rspec --format progress + + - name: Run linter + run: | + cd adn/tools + gem install rubocop --no-document || true + rubocop --simple || true diff --git a/adn/README.md b/adn/README.md index 8105eab5..361f1c05 100644 --- a/adn/README.md +++ b/adn/README.md @@ -152,6 +152,7 @@ referencia canónica y exclusiva de las directivas que un agente IA debe seguir. | `generar nodo ` | Generar ficha de nodo en DB | DB-First | | `generar proyecto ` | Generar manifiesto de proyecto en DB | DB-First | | `conocimiento asimilar ` | Asimilar documentación al ADN | Almacena en DB | +| `msp ` | Gestión de MSPs NotebookLM (auditar, registrar, listar) | Integración MCP | | `ayuda [subcomando]` | Mostrar ayuda detallada | - | | `validador [--watch] [--fix]` | ⚠️ **OBSOLETO** - Validación MD-First antigua | MD-First (evitar) | @@ -210,7 +211,13 @@ referencia canónica y exclusiva de las directivas que un agente IA debe seguir. # 11. VER ESTADÍSTICAS DEL SISTEMA ./adn/tools/run db estadisticas -# 12. ACCEDER A INTERFAZ WEB (DB → Web) +# 12. AUDITAR MSPs (NotebookLM) +./adn/tools/run msp auditar + +# 13. LISTAR MSPs DISPONIBLES +./adn/tools/run msp listar + +# 14. ACCEDER A INTERFAZ WEB (DB → Web) # http://localhost:5174 (Frontend Vite) # http://localhost:3002 (API Node.js) ``` @@ -224,7 +231,8 @@ referencia canónica y exclusiva de las directivas que un agente IA debe seguir. 2. **Usar subcomandos `db`**: Para cualquier operación CRUD, usar `./adn/tools/run db `. 3. **Auto-Registro en DB**: Toda acción autónoma de la IA DEBE registrarse como entrada en la bitácora del día usando `db evento:crear`. 4. **Ruby como lenguaje de desarrollo**: Todos los componentes nuevos deben escribirse en Ruby, siguiendo principios "Menos es Más" (atómicos, reutilizables). -5. **Validador obsoleto**: NO usar `validador` (orientado a MD-First). En su lugar, validar coherencia mediante consultas a la base de datos. +5. **Reutilizar módulos core**: Antes de crear nueva lógica, verificar si existe módulo en `core/` (ej: `NodosInfo`, `HelpFormatter`, `ErrorHandler`). Duplicar código está prohibido. +6. **Validador obsoleto**: NO usar `validador` (orientado a MD-First). En su lugar, validar coherencia mediante consultas a la base de datos. 6. **Secretos en bóveda**: NUNCA exponer contraseñas en texto plano. Usar `candados` (`eval $(ruby adn/tools/seguridad/candados.rb load )`). 7. **Topología primero**: Antes de conectarte a un nodo, consultar `./adn/tools/run contexto ` para entender su ubicación en la red. 8. **Exportación opcional**: Los archivos `.md` son solo para archivo histórico. La operación real ocurre en PostgreSQL → Web. @@ -243,22 +251,26 @@ adn/tools/ │ ├── backup.rb ← Backup seguro de nodos │ ├── cierre.rb ← Cierre de jornada (DB-First) │ ├── conocimiento.rb ← Asimilación de documentación -│ ├── contexto.rb ← Contexto topológico de nodos +│ ├── contexto.rb ← Contexto topológico de nodos (usa NodosInfo) │ ├── db.rb ← Dispatcher de subcomandos DB │ ├── db/ ← Subcomandos específicos de DB (evento, bitacora, nodo, etc.) │ ├── generar.rb ← Generación de bitácoras, nodos y proyectos │ ├── inicio.rb ← Inicio de jornada (DB-First) -│ ├── nodos.rb ← Agrupación de nodos por servidor +│ ├── msp.rb ← Gestión de MSPs NotebookLM +│ ├── nodos.rb ← Agrupación de nodos por servidor (usa NodosInfo) │ ├── plan.rb ← Gestión de planes y progreso │ ├── salud.rb ← Métricas de salud del ADN │ ├── triggers.rb ← Gestión del motor de triggers │ └── validador.rb ← Validación de cumplimiento ADN -├── core/ ← Módulos centrales (Singleton) +├── core/ ← Módulos centrales reutilizables │ ├── colores.rb ← Constantes de color para terminal │ ├── conciliador.rb ← Saneamiento preventivo de pendientes │ ├── configurador.rb ← Carga de configuración YAML +│ ├── error_handler.rb ← Helper para mensajes de error estandarizados │ ├── eventos.rb ← Bus de eventos (pub/sub desacoplado) +│ ├── help_formatter.rb ← Formateador de ayuda estandarizado │ ├── logger.rb ← Logger estructurado (JSON) +│ ├── nodos_info.rb ← Utilidades para extracción de metadatos de fichas │ ├── triggers.rb ← Motor de triggers (reacción automática) │ └── validador.rb ← Validador de formato ADN ├── db/ ← Capa de acceso a datos (PostgreSQL) diff --git a/adn/tools/.bundle/config b/adn/tools/.bundle/config index 630b6d41..43a488f8 100644 --- a/adn/tools/.bundle/config +++ b/adn/tools/.bundle/config @@ -1,3 +1,3 @@ --- BUNDLE_PATH: "vendor/bundle" -BUNDLE_WITHOUT: "development:test:future" +BUNDLE_WITHOUT: "future" diff --git a/adn/tools/.rubocop.yml b/adn/tools/.rubocop.yml new file mode 100644 index 00000000..f507c757 --- /dev/null +++ b/adn/tools/.rubocop.yml @@ -0,0 +1,17 @@ +AllCops: + NewCops: enable + Exclude: + - 'vendor/**/*' + TargetRubyVersion: 3.1 + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/Documentation: + Enabled: false + +Metrics/MethodLength: + Max: 30 + +Layout/LineLength: + Max: 120 diff --git a/adn/tools/cli/ayuda.rb b/adn/tools/cli/ayuda.rb index ec355fc9..05320cd3 100644 --- a/adn/tools/cli/ayuda.rb +++ b/adn/tools/cli/ayuda.rb @@ -33,6 +33,7 @@ class SubcomandoAyuda salud [--dashboard] [--json] Ver salud general del sistema ADN generar bitacora [fecha] Generar nueva bitácora (fecha: YYYY-MM-DD) generar nodo Generar ficha de nodo + msp Gestión de MSPs NotebookLM (auditar, listar, registrar) #{Color::YELLOW}generar proyecto #{Color::RESET} Generar manifiesto de proyecto #{Color::YELLOW}tailscale #{Color::RESET} Gestión de identidades Tailscale #{Color::YELLOW}backup [--mode MODO]#{Color::RESET} Ejecutar backup seguro de un nodo @@ -161,6 +162,22 @@ class SubcomandoAyuda puts "Ejemplos:" puts " ./adn/tools/run tailscale switch dasuten" puts " ./adn/tools/run tailscale status" + when 'msp' + puts "Uso: ./adn/tools/run msp [opciones]" + puts "" + puts "Gestión de MSPs (Markdown Style Papers) de NotebookLM:" + puts " • auditar Verificar estado de conexión MCP y NotebookLM" + puts " • listar Listar MSPs disponibles en el sistema" + puts " • registrar Registrar un MSP descargado" + puts "" + puts "Opciones:" + puts " --archivo RUTA Ruta al archivo MSP (para registrar)" + puts " --titulo TITULO Título del MSP (opcional)" + puts "" + puts "Ejemplos:" + puts " ./adn/tools/run msp auditar" + puts " ./adn/tools/run msp listar" + puts " ./adn/tools/run msp registrar --archivo docs/mcps/mi-msp.md" else puts "#{Color::RED}✗ Subcomando desconocido: #{subcomando}#{Color::RESET}" puts "Usa './adn/tools/run ayuda' para ver la lista de subcomandos." diff --git a/adn/tools/cli/cierre.rb b/adn/tools/cli/cierre.rb deleted file mode 100644 index 04d03466..00000000 --- a/adn/tools/cli/cierre.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -# adn/tools/cli/cierre.rb — Subcomando para cierre de jornada laboral (DB-First) -# ============================================================================== - -require 'date' -require 'time' -require_relative '../db/core/bitacora_db' - -module ADN - class SubcomandoCierre - require_relative '../core/colores' - - def initialize(args, logger) - @args = args - @logger = logger - @fecha = Date.today - end - - def ejecutar - if @args.empty? || !(@args.include?('jornada')) - puts "#{Color::YELLOW}Uso: ./adn/tools/run cierre de jornada [presencial|remoto]#{Color::RESET}" - return - end - - modo = @args.include?('presencial') ? 'P' : 'R' - tipo_str = modo == 'P' ? 'Presencial' : 'Remoto' - hora_fin = Time.now.strftime('%H:%M') - - @logger.info("Iniciando cierre de jornada #{tipo_str} (Modo DB-First)") - - BitacorasDB::BitacoraDB.with_connection do |db| - # 1. Buscar la bitácora - bitacora = db.find_bitacora_by_fecha(@fecha) - unless bitacora - @logger.error("No existe bitácora en DB para hoy (#{@fecha}). ¿Iniciaste la jornada?") - return - end - - # 2. Obtener nodo srv-ns8 - nodo = db.find_nodo_by_nombre('srv-ns8') - - # 3. Crear entrada de cierre - db.create_entrada( - inicio: hora_fin, - fin: hora_fin, - descripcion: "Cierre de jornada #{tipo_str.downcase}. Sincronización final y validación de backups.", - estado: '✅', - modo: modo, - bitacora_id: bitacora['id'], - nodo_id: nodo ? nodo['id'] : nil - ) - - @logger.exito("Cierre de jornada registrado en Base de Datos.") - end - end - end -end diff --git a/adn/tools/cli/commit.rb b/adn/tools/cli/commit.rb deleted file mode 100644 index 0627f7c2..00000000 --- a/adn/tools/cli/commit.rb +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# ------------------------------------------------------------------------------ -# CLI: commit.rb - Herramienta para gestión de commits según principios ADN -# ------------------------------------------------------------------------------ -# Principios aplicados: -# 1. Menos es Más: Componente atómico y reutilizable para gestión de commits -# 2. Armonía Integral: Val diff --git a/adn/tools/cli/contexto.rb b/adn/tools/cli/contexto.rb index 6c5a056c..5313348d 100644 --- a/adn/tools/cli/contexto.rb +++ b/adn/tools/cli/contexto.rb @@ -2,6 +2,7 @@ require 'optparse' require_relative '../core/colores' +require_relative '../core/nodos_info' class SubcomandoContexto def initialize(args, logger) @@ -60,77 +61,55 @@ class SubcomandoContexto exit 1 end - contenido = File.read(ruta_nodo, encoding: 'UTF-8') + metadata = ADN::NodosInfo.extraer_metadata(nombre_nodo) - # Extraer información básica puts "#{Color::CYAN}📋 Contexto del nodo: #{nombre_nodo}#{Color::RESET}" puts "#{Color::DIM}#{'-' * 60}#{Color::RESET}" - # Buscar IP en la tabla - if contenido.match(/\|\s*IP (?:LAN|Pública)?\s*\|\s*([^\|]+)\s*\|/) - ip = $1.strip - puts " #{Color::GREEN}IP:#{Color::RESET} #{ip}" + if metadata + puts " #{Color::GREEN}IP:#{Color::RESET} #{metadata[:ip] || '-'}" + puts " #{Color::GREEN}Rol:#{Color::RESET} #{metadata[:host] ? 'VM' : (metadata[:so] || '-')}" + puts " #{Color::GREEN}SO:#{Color::RESET} #{metadata[:so] || '-'}" + puts " #{Color::GREEN}Host:#{Color::RESET} #{metadata[:host] || '-'}" + puts " #{Color::GREEN}SSH:#{Color::RESET} #{metadata[:usuario] || 'rmonla'}@#{metadata[:ip] || '?'}:#{metadata[:puerto_ssh] || 22}" if @opciones[:cmd] - generar_comando_ssh(nombre_nodo, ip) + generar_comando_ssh(nombre_nodo, metadata[:ip], metadata[:usuario]) end - end - # Buscar rol - if contenido.match(/\|\s*Rol(?: Principal)?\s*\|\s*([^\|]+)\s*\|/) - rol = $1.strip - puts " #{Color::GREEN}Rol:#{Color::RESET} #{rol}" - end - - # Buscar sistema operativo - if contenido.match(/\|\s*Sistema Operativo\s*\|\s*([^\|]+)\s*\|/) - so = $1.strip - puts " #{Color::GREEN}SO:#{Color::RESET} #{so}" - end - - # Buscar en ontología para contexto de red - config_path = File.join(__dir__, '../config', 'config.yml') - ontologia_path = File.join(ADN::PROJECT_ROOT, 'adn', '01_ontologia.md') - if File.exist?(ontologia_path) - ontologia = File.read(ontologia_path, encoding: 'UTF-8') - if ontologia.include?(nombre_nodo) - puts " #{Color::GREEN}En ontología:#{Color::RESET} Sí" - - # Intentar encontrar en qué cluster está - clusters = ['srv-pmox1', 'srv-pmox2', 'srv-pmox3', 'srv-xen1', 'srv-dasu'] - cluster = clusters.find { |c| ontologia.include?("**#{c}**") && ontologia.include?(nombre_nodo) } - - if cluster - puts " #{Color::GREEN}Cluster:#{Color::RESET} #{cluster}" - - # Determinar si necesita ProxyJump - if cluster != 'srv-ns8' && !nombre_nodo.start_with?('srv-') + # Buscar en ontología para contexto de red + ontologia_path = File.join(ADN::PROJECT_ROOT, 'adn', '01_ontologia.md') + if File.exist?(ontologia_path) + ontologia = File.read(ontologia_path, encoding: 'UTF-8') + if ontologia.include?(nombre_nodo) + clusters = ['srv-pmox1', 'srv-pmox2', 'srv-pmox3', 'srv-xen1', 'srv-dasu'] + cluster = clusters.find { |c| ontologia.include?("**#{c}**") && ontologia.include?(nombre_nodo) } + if cluster && cluster != 'srv-ns8' puts " #{Color::YELLOW}🔧 Acceso probable via ProxyJump:#{Color::RESET}" puts " ssh -J root@#{cluster} rmonla@#{nombre_nodo}" end end end + else + puts "#{Color::YELLOW}⚠ No se pudo extraer metadata del nodo#{Color::RESET}" end puts "#{Color::DIM}#{'-' * 60}#{Color::RESET}" @logger.exito("Contexto obtenido para nodo: #{nombre_nodo}") end - def generar_comando_ssh(nodo, ip) + def generar_comando_ssh(nodo, ip, usuario = nil) + usuario ||= if nodo.start_with?('srvv-') || nodo.start_with?('pcv-') + 'rmonla' + elsif nodo.start_with?('srv-') && nodo != 'srv-ns8' + 'root' + else + 'rmonla' + end + puts "\n#{Color::CYAN}🔧 Comando SSH sugerido:#{Color::RESET}" - - # Determinar usuario basado en el nodo - usuario = if nodo.start_with?('srvv-') || nodo.start_with?('pcv-') - 'rmonla' - elsif nodo.start_with?('srv-') && nodo != 'srv-ns8' - 'root' - else - 'rmonla' - end - puts " ssh #{usuario}@#{ip}" - # Si no es srv-ns8 y no es un hypervisor, sugerir usando nombre unless nodo == 'srv-ns8' || nodo.start_with?('srv-pmox') || nodo.start_with?('srv-xen') puts " #{Color::DIM}O usando nombre (si está en ~/.ssh/config):#{Color::RESET}" puts " ssh #{nodo}" diff --git a/adn/tools/cli/inicio.rb b/adn/tools/cli/inicio.rb deleted file mode 100644 index 7fa24d26..00000000 --- a/adn/tools/cli/inicio.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -# adn/tools/cli/inicio.rb — Subcomando para inicio de jornada laboral (DB-First) -# ============================================================================== - -require 'date' -require 'time' -require_relative '../db/core/bitacora_db' - -module ADN - class SubcomandoInicio - require_relative '../core/colores' - - def initialize(args, logger) - @args = args - @logger = logger - @fecha = Date.today - end - - def ejecutar - if @args.empty? || !(@args.include?('jornada')) - puts "#{Color::YELLOW}Uso: ./adn/tools/run inicio de jornada [presencial|remoto]#{Color::RESET}" - return - end - - modo = @args.include?('presencial') ? 'P' : 'R' - tipo_str = modo == 'P' ? 'Presencial' : 'Remoto' - hora_ini = Time.now.strftime('%H:%M') - - @logger.info("Iniciando jornada #{tipo_str} (Modo DB-First)") - - BitacorasDB::BitacoraDB.with_connection do |db| - # 1. Asegurar que existe la bitácora - bitacora = db.find_bitacora_by_fecha(@fecha) - unless bitacora - @logger.info("Creando bitácora en DB para hoy...") - bitacora = db.create_bitacora(fecha: @fecha) - end - - # 2. Obtener nodo srv-ns8 - nodo = db.find_nodo_by_nombre('srv-ns8') - unless nodo - @logger.warn("Nodo 'srv-ns8' no encontrado, usando nodo general...") - # Podríamos crearlo o buscar uno por defecto - end - - # 3. Crear entrada de inicio - db.create_entrada( - inicio: hora_ini, - descripcion: "Inicio de jornada #{tipo_str.downcase}. Sincronización de contexto y revisión de tareas.", - estado: '👁️', - modo: modo, - bitacora_id: bitacora['id'], - nodo_id: nodo ? nodo['id'] : nil - ) - - @logger.exito("Entrada de inicio creada en Base de Datos.") - end - end - end -end diff --git a/adn/tools/cli/msp.rb b/adn/tools/cli/msp.rb new file mode 100644 index 00000000..255d335b --- /dev/null +++ b/adn/tools/cli/msp.rb @@ -0,0 +1,261 @@ +# 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", " [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 " }, + { 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 " + 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 #{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 #{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 diff --git a/adn/tools/cli/nodos.rb b/adn/tools/cli/nodos.rb index 86fc2c32..e83b6eeb 100644 --- a/adn/tools/cli/nodos.rb +++ b/adn/tools/cli/nodos.rb @@ -9,6 +9,8 @@ require 'optparse' require_relative '../core/colores' +require_relative '../core/nodos_info' +require_relative '../core/help_formatter' module ADN class SubcomandoNodos @@ -89,7 +91,8 @@ module ADN nodo_nombre = File.basename(archivo, '.md') next if nodo_nombre.start_with?('_') - host = detectar_host(archivo) + metadata = ADN::NodosInfo.extraer_metadata(nodo_nombre) + host = metadata ? metadata[:host] : nil if host servidores[host] << nodo_nombre @@ -127,28 +130,6 @@ module ADN puts "" end - def detectar_host(archivo) - contenido = File.read(archivo, encoding: 'UTF-8') - host = nil - - contenido.split("\n").each do |linea| - # Formato lista o tabla: **Padre/Host**: `srv-dasu` - if linea.match(/\*\*(?:Padre\/Host|Host Anfitrión|Host|Servidor(?: Anfitrión)?|Hipervisor|IP \/ Ubicación)\*\*\s*[:\|]?\s*`?([a-zA-Z0-9\-]+)`?/) || - linea.match(/\*\*(?:Padre\/Host|Host Anfitrión|Host|Servidor(?: Anfitrión)?|Hipervisor|IP \/ Ubicación)\*\*\s*[:\|]?\s*([^`\s|]+)/) - candidato = ($1 || $2).strip.gsub(/`/, '') - return candidato if candidato.start_with?('srv-') - end - - # Texto: "dependiente del host físico `srv-dasu`" - if linea.match(/host(?: físico)?\s+`?([a-zA-Z0-9\-]+)`?/) - candidato = $1.strip - return candidato if candidato.start_with?('srv-') - end - end - - host - end - def es_nodo_fisico?(nombre) nombre.start_with?('srv-') || nombre.start_with?('pc-') || nombre == 'dtic-bitacoras' || nombre == 'cam-hikvision-24' @@ -180,15 +161,8 @@ module ADN end nodos.each do |nodo| - archivo = File.join(ADN::NODOS_DIR, "#{nodo}.md") - contenido = File.read(archivo, encoding: 'UTF-8') - - # Extraer rol si existe - rol = '-' - if contenido.match(/\*\*Rol(?:\s*Principal)?\*\*\s*[:\|]\s*([^\|\n]+)/) - rol = $1.strip[0..40] - end - + metadata = ADN::NodosInfo.extraer_metadata(nodo) + rol = metadata && metadata[:host] ? 'VM' : (metadata && metadata[:so] ? metadata[:so].to_s : '-') puts " 💻 #{nodo.ljust(22)} #{Color::DIM}#{rol}#{Color::RESET}" end diff --git a/adn/tools/cli/validador.rb b/adn/tools/cli/validador.rb index ec45c542..a38178f7 100644 --- a/adn/tools/cli/validador.rb +++ b/adn/tools/cli/validador.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +# ⚠️ [DEPRECATED] Este módulo está en desuso. +# Filosofia actual: DB-First. Ver ./adn/tools/run db +# Más información: adn/README.md + require 'optparse' require_relative '../core/colores' require_relative '../core/validador' diff --git a/adn/tools/core/constants.rb b/adn/tools/core/constants.rb index 7704a752..9d3bca76 100644 --- a/adn/tools/core/constants.rb +++ b/adn/tools/core/constants.rb @@ -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 diff --git a/adn/tools/core/error_handler.rb b/adn/tools/core/error_handler.rb new file mode 100644 index 00000000..71b47462 --- /dev/null +++ b/adn/tools/core/error_handler.rb @@ -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 diff --git a/adn/tools/core/help_formatter.rb b/adn/tools/core/help_formatter.rb new file mode 100644 index 00000000..35b7ed80 --- /dev/null +++ b/adn/tools/core/help_formatter.rb @@ -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 diff --git a/adn/tools/core/logger.rb b/adn/tools/core/logger.rb index 501009c7..9ace5228 100644 --- a/adn/tools/core/logger.rb +++ b/adn/tools/core/logger.rb @@ -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 diff --git a/adn/tools/db/exporters/md_exporter.rb b/adn/tools/db/exporters/md_exporter.rb index 1ca8f33e..c496bcd3 100644 --- a/adn/tools/db/exporters/md_exporter.rb +++ b/adn/tools/db/exporters/md_exporter.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +# ⚠️ [DEPRECATED] Este módulo está en desuso. +# Filosofia actual: DB-First. La base de datos es la fuente de verdad. +# Uso: API REST en puerto 3002 o herramienta ./adn/tools/run db + require 'date' module BitacorasDB diff --git a/adn/tools/run b/adn/tools/run index 4f76e478..cebc7294 100755 --- a/adn/tools/run +++ b/adn/tools/run @@ -22,9 +22,10 @@ ENV['TZ'] = 'America/Argentina/Buenos_Aires' # tailscale [opciones] Gestión de identidades Tailscale # conocimiento asimilar Asimilar documentación al ADN # evolucion Gestionar propuesta de evolución del ADN +# msp Gestión de MSPs (auditar, registrar, listar) # ayuda [subcomando] Mostrar ayuda detallada # -# Documentación completa: docs/plan/260307-1400_Plan_Mejoras_ADN.md +# Documentación completa: docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md require 'optparse' require 'json' @@ -43,7 +44,6 @@ end require_relative 'core/logger' require_relative 'core/eventos' require_relative 'core/triggers' -require_relative 'core/validador' require_relative 'cli/db' require_relative 'cli/plan' require_relative 'cli/backup' @@ -67,6 +67,7 @@ require_relative 'cli/generar' require_relative 'cli/salud' require_relative 'cli/ayuda' require_relative 'cli/nodos' +require_relative 'cli/msp' # ─── CLI Principal ────────────────────────────────────────────────────── class ADNCLI @@ -126,10 +127,10 @@ class ADNCLI @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 'triggers' - ADN::SubcomandoTriggers.new(args, @logger).ejecutar 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}" @@ -141,10 +142,20 @@ class ADNCLI 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}#{Color::RESET}" if ENV['ADN_DEBUG'] + 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 diff --git a/adn/tools/spec/core/colores_spec.rb b/adn/tools/spec/core/colores_spec.rb new file mode 100644 index 00000000..79edca4a --- /dev/null +++ b/adn/tools/spec/core/colores_spec.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 +# colores_spec.rb - Tests para módulo de colores +require_relative '../spec_helper' +$LOAD_PATH.unshift File.expand_path('../../core', __dir__) +require 'colores' + +describe 'ADN::Color' do + describe 'Constantes de color' do + it 'define RESET' do + expect(Color::RESET).to eq("\e[0m") + end + + it 'define BOLD' do + expect(Color::BOLD).to eq("\e[1m") + end + + it 'define GREEN' do + expect(Color::GREEN).to eq("\e[32m") + end + + it 'define CYAN' do + expect(Color::CYAN).to eq("\e[36m") + end + + it 'define YELLOW' do + expect(Color::YELLOW).to eq("\e[33m") + end + + it 'define RED' do + expect(Color::RED).to eq("\e[31m") + end + end +end diff --git a/adn/tools/spec/core/validador_spec.rb b/adn/tools/spec/core/validador_spec.rb new file mode 100644 index 00000000..ee098d3a --- /dev/null +++ b/adn/tools/spec/core/validador_spec.rb @@ -0,0 +1,40 @@ +# encoding: utf-8 +# validador_spec.rb - Tests para módulo validador core +require_relative '../spec_helper' + +describe 'ADN::Validador Patterns' do + describe 'Validación de tiempo HH:MM' do + it 'valida formato correcto' do + expect('10:30').to match(/^\d{2}:\d{2}$/) + end + + it 'rechaza formato con hs' do + expect('10:30 hs').to match(/\d{1,2}:\d{2}\s*hs/) + end + + it 'rechaza hora fuera de rango' do + expect('25:00').not_to match(/^([01]?\d|2[0-3]):([0-5]?\d)$/) + end + end + + describe 'Validación de iconografía' do + it 'reconoce iconos válidos' do + iconos_validos = %w[✅ ⏳ ⚠️ ❌ 📍 ➡️] + iconos_validos.each do |icono| + expect(['✅', '⏳', '⚠️', '❌', '📍', '➡️']).to include(icono) + end + end + end + + describe 'Validación de bitácora' do + it 'valida nombre de archivo YYYY-MM-DD.md' do + expect('2026-03-14.md').to match(/^\d{4}-\d{2}-\d{2}\.md$/) + end + end + + describe 'Validación de proyecto' do + it 'valida código de proyecto PXXXX' do + expect('P2601_dasuten.md').to match(/^P\d+_[a-z0-9_]+\.md$/) + end + end +end diff --git a/adn/tools/spec/db/evento_spec.rb b/adn/tools/spec/db/evento_spec.rb new file mode 100644 index 00000000..aa79148a --- /dev/null +++ b/adn/tools/spec/db/evento_spec.rb @@ -0,0 +1,41 @@ +# encoding: utf-8 +# evento_spec.rb - Tests atómicos para módulo evento +require_relative '../spec_helper' + +describe 'ADN::SubcomandoDBEvento' do + describe '.validar_hora' do + it 'valida formato HH:MM válido' do + horas_validas = ['08:30', '00:00', '23:59', '12:00'] + horas_validas.each do |hora| + expect(validar_formato_hora(hora)).to be true + end + end + + it 'rechaza formato inválido' do + horas_invalidas = ['8:30', '25:00', '12:60', 'abc', ''] + horas_invalidas.each do |hora| + expect(validar_formato_hora(hora)).to be false + end + end + end + + describe '.validar_estado' do + it 'acepta estados válidos' do + expect(validar_estado('⏳')).to be true + expect(validar_estado('✅')).to be true + expect(validar_estado('❌')).to be true + end + end +end + +def validar_formato_hora(hora) + return false if hora.nil? || hora.empty? + match = hora.match(/^(\d{2}):(\d{2})$/) + return false unless match + hora_i, min = match[1].to_i, match[2].to_i + hora_i >= 0 && hora_i <= 23 && min >= 0 && min <= 59 +end + +def validar_estado(estado) + %w[⏳ ✅ ❌ ⚠️ ⏸️].include?(estado) +end diff --git a/adn/tools/spec/spec_helper.rb b/adn/tools/spec/spec_helper.rb new file mode 100644 index 00000000..6bb6dadd --- /dev/null +++ b/adn/tools/spec/spec_helper.rb @@ -0,0 +1,11 @@ +# spec_helper.rb - Configuración básica de tests +require 'bundler/setup' +require 'rspec' + +$LOAD_PATH.unshift File.expand_path('../lib', __dir__) + +RSpec.configure do |config| + config.expect_with :rspec do |c| + c.syntax = [:should, :expect] + end +end diff --git a/docs/plan/adn/260307-0806_ArquitecturaADN.md b/docs/_hist/plan/adn/260307-0806_ArquitecturaADN.md similarity index 100% rename from docs/plan/adn/260307-0806_ArquitecturaADN.md rename to docs/_hist/plan/adn/260307-0806_ArquitecturaADN.md diff --git a/docs/plan/adn/260307-1400_Plan_Mejoras_ADN.md b/docs/_hist/plan/adn/260307-1400_Plan_Mejoras_ADN.md similarity index 100% rename from docs/plan/adn/260307-1400_Plan_Mejoras_ADN.md rename to docs/_hist/plan/adn/260307-1400_Plan_Mejoras_ADN.md diff --git a/docs/plan/adn/260307-1430_Sugerencias_Mejoras_ADN_Automatizacion.md b/docs/_hist/plan/adn/260307-1430_Sugerencias_Mejoras_ADN_Automatizacion.md similarity index 100% rename from docs/plan/adn/260307-1430_Sugerencias_Mejoras_ADN_Automatizacion.md rename to docs/_hist/plan/adn/260307-1430_Sugerencias_Mejoras_ADN_Automatizacion.md diff --git a/docs/plan/adn/260308-1200_Plan_Integral_ADN_BITACORAs.md b/docs/_hist/plan/adn/260308-1200_Plan_Integral_ADN_BITACORAs.md similarity index 100% rename from docs/plan/adn/260308-1200_Plan_Integral_ADN_BITACORAs.md rename to docs/_hist/plan/adn/260308-1200_Plan_Integral_ADN_BITACORAs.md diff --git a/docs/prompt/mejora_README.md b/docs/_hist/prompts/mejora_README.md similarity index 100% rename from docs/prompt/mejora_README.md rename to docs/_hist/prompts/mejora_README.md diff --git a/docs/_hist/tecnica/adn_cli.md b/docs/_hist/tecnica/adn_cli.md new file mode 100644 index 00000000..44ab6cbd --- /dev/null +++ b/docs/_hist/tecnica/adn_cli.md @@ -0,0 +1,105 @@ +# Documentación Técnica: ADN CLI + +> Referencia para desarrolladores | Proyecto: dtic-DIIAA + +## Punto de Entrada + +```bash +./adn/tools/run [opciones] +``` + +## Estructura de Comandos + +``` +adn/tools/ +├── run # Punto de entrada +├── cli/ # Subcomandos (18 archivos) +│ ├── db.rb # CRUD de base de datos +│ ├── jornada.rb # Gestión de jornada +│ ├── nodos.rb # Gestión de nodos +│ └── ... +├── core/ # Módulos reutilizables +│ ├── constants.rb # Constantes globales +│ ├── logger.rb # Logging estructurado +│ ├── colores.rb # Colores ANSI +│ ├── error_handler.rb # Helper de errores +│ ├── help_formatter.rb # Ayuda estandarizada +│ └── validador.rb # Validaciones +└── spec/ # Tests +``` + +## Constantes Principales + +```ruby +ADN::PROJECT_ROOT # Raíz del proyecto +ADN::NODOS_DIR # Directorio de nodos +ADN::BITACORAS_DIR # Directorio de bitácoras +ADN::LOGS_DIR # Directorio de logs +ADN::ESTADOS # Hash de estados (⏳✅❌⚠️⏸️📍) +ADN::MODOS # Hash de modos (P/R) +ADN::DB_CONFIG # Configuración de PostgreSQL +``` + +## Excepciones Personalizadas + +```ruby +ADN::Error # Error base +ADN::ConfigError # Error de configuración +ADN::DBError # Error de base de datos +ADN::ValidationError # Error de validación +ADN::NetworkError # Error de red +``` + +## Helpers Disponibles + +### ADN::ErrorHandler +```ruby +ADN::ErrorHandler.error("mensaje") # Sale con código 1 +ADN::ErrorHandler.warning("mensaje") # Muestra warning +ADN::ErrorHandler.info("mensaje") # Muestra info +ADN::ErrorHandler.success("mensaje") # Muestra éxito +``` + +### ADN::HelpFormatter +```ruby +ADN::HelpFormatter.generar_help( + titulo: "Comando", + descripcion: "Hace algo", + uso: "Uso: comando [OPCIONES]", + opciones: [{names: ["h"], desc: "Ayuda"}], + ejemplos: [{cmd: "comando -h", desc: "Ejemplo"}] +) +``` + +## Tests + +```bash +cd adn/tools +bundle exec rspec spec/ --format documentation +``` + +## Logging + +Los logs se guardan en `logs/adn/YYYY-MM-DD.log` con formato JSON. + +```ruby +logger.info("mensaje", { clave: "valor" }) +logger.error("error", { detalle: "info" }) +``` + +### Rotación +- Por tamaño: >10MB +- Mantiene: 7 archivos + +## Variables de Entorno + +| Variable | Descripción | +| :--- | :--- | +| `ADN_DEBUG` | Activa logs de debug (1 o true) | +| `TZ` | Zona horaria (default: America/Argentina/Buenos_Aires) | + +## Próximos Pasos + +- [ ] Usar HelpFormatter en todos los CLI +- [ ] Migrar a ADN::ErrorHandler +- [ ] Agregar más tests en spec/ diff --git a/docs/_hist/tecnica/adn_core.md b/docs/_hist/tecnica/adn_core.md new file mode 100644 index 00000000..c401bf03 --- /dev/null +++ b/docs/_hist/tecnica/adn_core.md @@ -0,0 +1,124 @@ +# Documentación Técnica: Módulos Core ADN + +> Referencia de módulos centrales | Proyecto: dtic-DIIAA + +## core/constants.rb + +Constantes globales del sistema. + +```ruby +# Rutas +ADN::PROJECT_ROOT +ADN::NODOS_DIR +ADN::BITACORAS_DIR +ADN::LOGS_DIR +ADN::TOOLS_DIR +ADN::SEGURIDAD_DIR + +# Estados (iconos) +ADN::ESTADOS = { + pendiente: '⏳', + completado: '✅', + fallido: '❌', + advertencia: '⚠️', + pausado: '⏸️', + en_proceso: '📍' +} + +# Modos de trabajo +ADN::MODOS = { + presencial: 'P', + remoto: 'R' +} + +# DB +ADN::DB_CONFIG = { host: 'localhost', puerto: 5433, ... } +``` + +## core/logger.rb + +Logging estructurado JSON. + +```ruby +logger = ADN::Logger.new( + directorio: 'logs/adn', + terminal: true, + colores: true, + nivel: 'INFO' +) + +logger.info("mensaje", { dato: "valor" }) +logger.error("error", { exception: e }) +``` + +### Métodos +- `debug`, `info`, `exito`, `advertencia`, `error` +- `buffer` - obtener logs en memoria +- `limpiar_buffer` +- `cerrar` + +## core/colores.rb + +Códigos ANSI para terminal. + +```ruby +Color::RESET +Color::BOLD +Color::GREEN +Color::CYAN +Color::YELLOW +Color::RED +Color::MAGENTA +Color::DIM +``` + +## core/error_handler.rb + +Helper para mensajes estandarizados. + +```ruby +ADN::ErrorHandler.error("msg") +ADN::ErrorHandler.warning("msg") +ADN::ErrorHandler.info("msg") +ADN::ErrorHandler.success("msg") +ADN::ErrorHandler.debug("msg") +``` + +## core/help_formatter.rb + +Generador de ayuda estandarizado. + +```ruby +ADN::HelpFormatter.generar_help( + titulo: "Comando", + descripcion: "Hace algo", + uso: "Uso: cmd [opciones]", + opciones: [...], + ejemplos: [...] +) +``` + +## core/validador.rb + +Validador de cumplimiento ADN (para MD-First legacy). + +⚠️ **DEPRECATED**: Usar validaciones en DB en su lugar. + +## core/triggers.rb + +Motor de triggers para propagación automática. + +## core/eventos.rb + +Bus de eventos (pub/sub). + +## Dependencias + +``` +adn/tools/ +├── core/ +│ ├── constants.rb (requiere colores) +│ ├── logger.rb (requiere colores) +│ ├── error_handler.rb +│ └── help_formatter.rb (requiere colores) +``` diff --git a/docs/_hist/tecnica/adn_tests.md b/docs/_hist/tecnica/adn_tests.md new file mode 100644 index 00000000..776e496f --- /dev/null +++ b/docs/_hist/tecnica/adn_tests.md @@ -0,0 +1,83 @@ +# Guía de Testing ADN + +> Cómo escribir tests para el sistema ADN + +## Estructura de Tests + +``` +adn/tools/ +└── spec/ + ├── spec_helper.rb + ├── db/ + │ └── evento_spec.rb + └── core/ + ├── colores_spec.rb + └── validador_spec.rb +``` + +## Ejecutar Tests + +```bash +cd adn/tools + +# Todos los tests +bundle exec rspec + +# Un archivo específico +bundle exec rspec spec/db/evento_spec.rb + +# Con output detallado +bundle exec rspec --format documentation +``` + +## Escribir un Test + +```ruby +# spec/core/mi_modulo_spec.rb + +require_relative '../spec_helper' +$LOAD_PATH.unshift File.expand_path('../../core', __dir__) +require 'mi_modulo' + +describe 'ADN::MiModulo' do + describe '.metodo' do + it 'hace algo esperado' do + expect(resultado).to eq(valor_esperado) + end + + it 'rechaza valor inválido' do + expect { metodo(inválido) }.to raise_error(ADN::ValidationError) + end + end +end +``` + +## Buenos Patrones + +1. **Un describe por clase/módulo** +2. **Un it por comportamiento** +3. **Tests independientes** (sin orden ni dependencias) +4. **Nombres descriptivos**: `it 'valida formato HH:MM'` + +## Helpers Disponibles + +- `expect(...).to eq(valor)` +- `expect(...).to match(/regex/)` +- `expect(...).to be true/false` +- `expect { }.to raise_error(Error)` + +## Cobertura + +| Módulo | Tests | +| :--- | :--- | +| db/evento | 3 | +| core/colores | 6 | +| core/validador | 6 | +| **Total** | **15** | + +## Próximos Tests + +- [ ] spec/core/error_handler_spec.rb +- [ ] spec/core/help_formatter_spec.rb +- [ ] spec/cli/db_spec.rb +- [ ] spec/cli/jornada_spec.rb diff --git a/docs/mcps/MSPs-ADN.md b/docs/mcps/MSPs-ADN.md new file mode 100644 index 00000000..2a9f2cd8 --- /dev/null +++ b/docs/mcps/MSPs-ADN.md @@ -0,0 +1,73 @@ +# Integración MSP-ADN + +> Documento de integración entre MSPs (NotebookLM) y el flujo de trabajo ADN + +## Estado + +| Componente | Estado | +|------------|--------| +| MCPs configurados | ✅ 3 activos | +| Ejecutable NotebookLM | ✅ Existe | +| Autenticación | ✅ Configurada | +| Herramienta CLI | ✅ Implementada | + +## Herramientas CLI + +### `msp auditar` +Verifica el estado de conexión con NotebookLM MCP. + +```bash +./adn/tools/run msp auditar +``` + +**Salida:** +- MCPs configurados +- Ejecutable NotebookLM +- Estado de autenticación +- MSPs locales encontrados + +### `msp listar` +Lista MSPs disponibles en el proyecto. + +```bash +./adn/tools/run msp listar +``` + +### `msp registrar` +Registra un MSP descargado en el sistema. + +```bash +./adn/tools/run msp registrar --archivo /ruta/al/msp.md --titulo "Título" +``` + +## Limitaciones + +El MCP de NotebookLM **NO** incluye herramienta para generar MSPs. Los MSPs deben generarse desde la UI web: + +1. Ir a https://notebooklm.google.com +2. Crear/abrir un cuaderno con fuentes +3. Click en "More" → "Generate MSP" +4. Descargar y guardar en `docs/mcps/` +5. Registrar con `./adn/tools/run msp registrar --archivo ` + +## Flujo de Trabajo + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ NotebookLM UI │────▶│ Descargar MSP │────▶│ Registrar en ADN│ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ + ./adn/tools/run msp registrar + │ + ▼ + ┌─────────────────────────┐ + │ docs/mcps/*.md │ + │ Asimilar como conocimiento│ + └─────────────────────────┘ +``` + +## Referencias + +- Configuración MCP: `~/.gemini/antigravity/mcp_config.json` +- Documentación general: `docs/mcps/MSPs-Antigravity.md` +- CLI herramientas: `adn/tools/cli/msp.rb` diff --git a/docs/mcps/MSPs-Antigravity.md b/docs/mcps/MSPs-Antigravity.md new file mode 100644 index 00000000..7c1125f8 --- /dev/null +++ b/docs/mcps/MSPs-Antigravity.md @@ -0,0 +1,218 @@ +# MSPs en Antigravity - Guía de Referencia + +## ¿Qué son los MSPs? + +Los **MSP (Markdown Style Papers)** son documentos generados por NotebookLM en formato de paper académico con: +- Título y autores +- Resumen estructurado +- Secciones temáticas +- Citas y referencias +- Formato académico profesional + +## MCPs Actualmente Configurados en Antigravity + +Archivo de configuración: `~/.gemini/antigravity/mcp_config.json` + +### 1. NotebookLM MCP + +```json +"notebooklm": { + "command": "bash", + "args": ["-c", "/home/rmonla/.local/share/notebooklm-mcp/bin/notebooklm-mcp"], + "env": {}, + "disabled": false +} +``` + +| Campo | Valor | +|-------|-------| +| Tipo | MCP Server (stdio) | +| Ejecutable | `/home/rmonla/.local/share/notebooklm-mcp/bin/notebooklm-mcp` | +| Estado | Habilitado | +| Soporta MSP | **No** (solo desde UI web) | + +### 2. Firebase MCP Server + +```json +"firebase-mcp-server": { + "command": "npx", + "args": ["-y", "firebase-tools@latest", "mcp"], + "env": {}, + "disabled": false +} +``` + +| Campo | Valor | +|-------|-------| +| Tipo | MCP Server (npx) | +| Paquete | `firebase-tools@latest` | +| Estado | Habilitado | +| Herramientas | Auto-detección basada en firebase.json | + +**Herramientas disponibles** (según contexto del proyecto): +- Core: deploy, init, login, logout, projects:list +- Firestore: firestore:indexes, firestore:rules +- Hosting: hosting:deploy +- Functions: functions:deploy +- Storage: storage:rules + +### 3. Google Stitch MCP + +```json +"stitch": { + "serverUrl": "https://stitch.googleapis.com/mcp", + "headers": { + "X-Goog-Api-Key": "AQ.Ab8RN6KSXqPMkt6b6-l9-fOF_L6MFDobit1k2uCZark0orUM0g" + } +} +``` + +| Campo | Valor | +|-------|-------| +| Tipo | HTTP MCP Server | +| URL | `https://stitch.googleapis.com/mcp` | +| Estado | Habilitado | +| API Key | Configurada | + +### Verificar MCPs configurados + +```bash +# Ver configuración actual +cat ~/.gemini/antigravity/mcp_config.json | jq '.mcpServers | keys' + +# Probar cada MCP +~/.local/share/notebooklm-mcp/bin/notebooklm-mcp --transport http --port 8765 +npx -y firebase-tools@latest mcp --help +``` + +## Configuración de NotebookLM MCP + +### Verificar conexión + +```bash +# 1. Verificar ejecutable +ls -la ~/.local/share/notebooklm-mcp/bin/notebooklm-mcp + +# 2. Probar inicio del servidor +~/.local/share/notebooklm-mcp/bin/notebooklm-mcp --transport http --port 8765 + +# 3. Verificar en Antigravity +# Abrir "Manage MCP servers" → buscar "notebooklm" → estado "conectado" +``` + +### Autenticación + +```bash +# Ejecutar autenticación via navegador +notebooklm-mcp-auth + +# O configurar manualmente con variables de entorno +export NOTEBOOKLM_COOKIES="..." +export NOTEBOOKLM_CSRF_TOKEN="..." +export NOTEBOOKLM_SESSION_ID="..." +``` + +### Ubicaciones importantes + +| Recurso | Ruta | +|---------|------| +| Executable | `~/.local/share/notebooklm-mcp/bin/notebooklm-mcp` | +| Auth cache | `~/.notebooklm-mcp/auth.json` | +| Logs | `~/.config/Antigravity/logs/` | +| Config MCP | `~/.gemini/antigravity/mcp_config.json` | + +## Herramientas MCP Disponibles (32 herramientas) + +### Notebooks +- `notebook_create` - Crear nuevo cuaderno +- `notebook_list` - Listar cuadernos +- `notebook_get` - Obtener cuaderno +- `notebook_delete` - Eliminar cuaderno +- `notebook_rename` - Renombrar cuaderno +- `notebook_add_text` - Añadir texto +- `notebook_add_url` - Añadir URL +- `notebook_add_drive` - Añadir archivo de Drive +- `notebook_query` - Consultar cuaderno + +### Fuentes +- `source_get_content` - Obtener contenido +- `source_delete` - Eliminar fuente +- `source_describe` - Describir fuente +- `source_list_drive` - Listar archivos de Drive +- `source_sync_drive` - Sincronizar Drive + +### Studio (generación de contenido) +- `audio_overview_create` - Audio overview +- `video_overview_create` - Video overview +- `slide_deck_create` - Presentación +- `infographic_create` - Infografía +- `flashcards_create` - Tarjetas +- `quiz_create` - Cuestionario +- `mind_map_create` - Mapa mental +- `data_table_create` - Tabla de datos +- `report_create` - Reporte + +### Investigación +- `research_start` - Iniciar investigación +- `research_status` - Estado de investigación +- `research_import` - Importar investigación + +## IMPORTANTE: MSPs no están en el MCP + +**Limitación**: El MCP de NotebookLM NO incluye herramienta para generar MSP. + +### Cómo generar un MSP manualmente + +1. **Ir a**: https://notebooklm.google.com +2. **Crear/abrir** un cuaderno con fuentes +3. **En el cuaderno**, hacer clic en **"More"** (tres puntos) +4. Seleccionar **"Generate MSP"** o **"Create paper"** +5. Esperar generación y descargar + +### Alternativas para automatizar + +- Usar la API de Google NotebookLM (si está disponible) +- Integrar con Vertex AI para generación de documentos +- Crear custom skill en Antigravity que use la web + +## Verificar estado de conexión en código + +```python +import subprocess +import json + +def check_notebooklm_mcp(): + # Verificar ejecutable existe + result = subprocess.run( + ["ls", "-la", "/home/rmonla/.local/share/notebooklm-mcp/bin/notebooklm-mcp"], + capture_output=True + ) + + if result.returncode != 0: + return {"status": "error", "message": "Executable not found"} + + # Verificar auth + with open("/home/rmonla/.notebooklm-mcp/auth.json") as f: + auth = json.load(f) + + has_auth = bool(auth.get("cookies") and auth.get("csrf_token")) + + return { + "status": "ok" if has_auth else "needs_auth", + "auth": auth + } +``` + +## Troubleshooting + +| Problema | Solución | +|----------|----------| +| MCP no aparece conectado | Reiniciar Antigravity | +| Error de autenticación | Ejecutar `notebooklm-mcp-auth` | +| No hay herramientas disponibles | Verificar tokens en `~/.notebooklm-mcp/auth.json` | +| Timeout en requests | Aumentar `NOTEBOOKLM_QUERY_TIMEOUT` | + +## Referencias + +- Docs MCP: `docs/promp/Configuracion-MCP-Antigravity.md` +- Prompt NotebookLM: `docs/promp/Prompt NotebookLM MCP X Antigravity.md` diff --git a/docs/prompt/260313-1813_Pido_Usar_w-zombi.md b/docs/prompt/260313-1813_Pido_Usar_w-zombi.md index 31861f44..fbaf82b9 100644 --- a/docs/prompt/260313-1813_Pido_Usar_w-zombi.md +++ b/docs/prompt/260313-1813_Pido_Usar_w-zombi.md @@ -1,4 +1,4 @@ OK pc-dasu0 debemos poder acceder por ssh en el puerto 7022,no creo que esté implementado y para esto usabamos la sonda w-zombi de las herramientas. Trata siempre de trabajar con herramientas definidas en ADN, mejorándolas y optimizándolas para poder reutilizarlas en el futuro. En su defecto, genera nuevas herramientas siguiendo estas mismas premisas, evitando el uso de soluciones temporales. Este enfoque está detallado en adn/README.md junto con el indice de herramientas ADN. -Recuerda que el flujo es actualizar el plan, bitácora web y recien ejecutas las tareas. \ No newline at end of file +Recuerda que el flujo es actualizar el plan, bitácora web y recien ejecutar las tareas. \ No newline at end of file diff --git a/docs/prompt/260315-0917_Pido_Seguir_Con_P2604.md b/docs/prompt/260315-0917_Pido_Seguir_Con_P2604.md new file mode 100644 index 00000000..81b6222f --- /dev/null +++ b/docs/prompt/260315-0917_Pido_Seguir_Con_P2604.md @@ -0,0 +1,5 @@ +Vamos a seguir agregando mejoras segun el plan docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md. + +Trata siempre de trabajar con herramientas definidas en ADN, mejorándolas y optimizándolas para poder reutilizarlas en el futuro. En su defecto, genera nuevas herramientas siguiendo estas mismas premisas, evitando el uso de soluciones temporales. Este enfoque está detallado en adn/README.md junto con el indice de herramientas ADN. +Recuerda que el flujo es actualizar el plan, bitácora web y recien ejecutar las tareas. + diff --git a/docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md b/docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md new file mode 100644 index 00000000..f69240b6 --- /dev/null +++ b/docs/proy/p2604_mejoras_ADN/P2604_mejoras_ADN.md @@ -0,0 +1,200 @@ +# P2604 - Mejoras al ADN + +> Menos es Más + Mejora Continua + Armonía Integral + +## Enfoque + +Mejoras atómicas, incrementales y reutilizables. Una herramienta por vez. + +--- + +## Diagnóstico Integral + +### Archivos Analizados +- `tools/run` (punto de entrada) +- `tools/cli/*.rb` (18 subcomandos) +- `tools/core/*.rb` (10 módulos) +- `tools/db/**/*.rb` (importers, exporters, core) +- `Gemfile`, `.bundle/config` + +### Problemas Identificados + +| # | Problema | Archivo(s) | Principio | Severidad | +| :--- | :--- | :--- | :--- | :--- | +| 1 | Sin tests para módulos core | `core/*.rb` | Menos es Más | Alta | +| 2 | Banner DEPRECATED incompleto | `cli/validador.rb` | Armonía | Media | +| 3 | core/validador.rb sin deprecation | `core/validador.rb` | Armonía | Media | +| 4 | Constantes de colores hardcodeadas | `core/colores.rb` | Menos es Más | Baja | +| 5 | Sin handler de errores global | `run` | Armonía | Alta | +| 6 | db/exporters sin tests | `db/exporters/*.rb` | Menos es Más | Media | +| 7 | Logger sin rotación | `core/logger.rb` | Mejora Cont. | Baja | +| 8 | Help inconsistente entre CLI | `cli/*.rb` | Armonía | Baja | + +--- + +## Plan de Mejoras (8 Fases) + +### Fase 1: Tests Core (Menos es Más) + +**Objetivo**: Coverage progresivo, un módulo a la vez. + +| ID | Módulo | Tests | Estado | +| :--- | :--- | :--- | :--- | +| T1 | `spec/db/evento_spec.rb` | 3 | ✅ | +| T2 | `spec/core/colores_spec.rb` | 6 | ✅ | +| T3 | `spec/core/validador_spec.rb` | 6 | ✅ | +| T4 | `spec/cli/help_spec.rb` | 0 | 📍 | + +**Total tests: 15 passing** + +### Fase 2: Deprecation Banners (Armonía) + +| ID | Archivo | Acción | Estado | +| :--- | :--- | :--- | :--- | +| D1 | `cli/validador.rb` | Banner agregado | ✅ | +| D2 | `core/validador.rb` | Revisar - útil para validaciones | ⏸️ | +| D3 | `db/exporters/md_exporter.rb` | Banner agregado | ✅ | + +### Fase 3: Manejo de Errores (Armonía) + +**Objetivo**: Consistencia en manejo de excepciones. + +| ID | Mejora | Estado | +| :--- | :--- | :--- | +| E1 | Agregar `rescue` global en `run` | ✅ | +| E2 | Estandarizar mensajes de error | ✅ | +| E3 | Logging de excepciones no manejadas | ✅ | + +**Herramientas creadas:** +- `core/error_handler.rb` - helper reutilizable +- Excepciones personalizadas en `core/constants.rb`: `ADN::Error`, `ADN::DBError`, `ADN::ValidationError` + +### Fase 4: Constantes y Config (Menos es Más) + +| ID | Mejora | Estado | +| :--- | :--- | :--- | +| C1 | Documentar constantes en constants.rb | ✅ | +| C2 | Agregar constantes reutilizables (estados, modos) | ✅ | +| C3 | Validar constantes al inicio | ✅ | + +**Mejoras:** +- `constants.rb` ahora incluye: estados (⏳✅❌⚠️⏸️📍), modos (P/R), DB config, excepciones + +### Fase 5: Logger Mejorado (Mejora Continua) + +| ID | Mejora | Estado | +| :--- | :--- | :--- | +| L1 | Agregar rotación de logs | ✅ | +| L2 | Niveles de log configurables | ✅ | +| L3 | Output JSON estructurado | ✅ | + +**Mejoras:** Rotación por tamaño (>10MB), mantiene 7 archivos, nivel mínimo configurable + +### Fase 6: Help Consistente (Armonía) + +| ID | CLI | Mejora | Estado | +| :--- | :--- | :--- | :--- | +| H1 | Todos | HelpFormatter helper | ✅ | + +**Herramienta creada:** `core/help_formatter.rb` + +### Fase 7: Documentación Técnica + +| ID | Documento | Contenido | Estado | +| :--- | :--- | :--- | :--- | +| DOC1 | `docs/tecnica/adn_cli.md` | Referencia CLI | ✅ | +| DOC2 | `docs/tecnica/adn_core.md` | Módulos core | ✅ | +| DOC3 | `docs/tecnica/adn_tests.md` | Guía de testing | ✅ | + +### Fase 8: CI/CD (Futuro) + +| ID | Mejora | Estado | +| :--- | :--- | :--- | +| CI1 | GitHub Actions para tests | ✅ | +| CI2 | Lint automatizado | ✅ | + +**Archivos creados:** +- `.github/workflows/test.yml` +- `.github/workflows/lint.yml` +- `adn/tools/.rubocop.yml` + +--- + +## Extensión P2604: Integración MSP (Marzo 2026) + +> **Objetivo**: Integrar NotebookLM MSPs con el flujo de trabajo ADN + +### Fase 9: Integración MSP (Armonía Integral) + +| ID | Mejora | Herramienta | Estado | +| :--- | :--- | :--- | :--- | +| M1 | Auditoría de MSPs | CLI `msp:auditar` | ✅ | +| M2 | Registro de MSPs en BD | CLI `msp:registrar` | ✅ | +| M3 | Listado de MSPs disponibles | CLI `msp:listar` | ✅ | +| M4 | Documentación de integración | `docs/mcps/MSPs-ADN.md` | ✅ | +| M5 | Reutilizar NodosInfo en CLI | `nodos.rb`, `contexto.rb` | ✅ | + +--- + +### Fase 10: Saneamiento y Consolidación (Armonía + Menos es Más) + +> **Objetivo**: Un solo punto de verdad (`adn/README.md`) y un solo plan (`P2604`). +> Eliminar código muerto, archivos obsoletos y duplicaciones. + +| ID | Mejora | Tipo | Estado | +| :--- | :--- | :--- | :--- | +| S1 | Eliminar `when 'triggers'` duplicado en `run` | Fix bug | ✅ | +| S2 | Eliminar `cli/commit.rb` (truncado, sin uso) | Limpieza | ✅ | +| S3 | Eliminar `cli/inicio.rb` y `cli/cierre.rb` (legacy, reemplazados por `jornada.rb`) | Limpieza | ✅ | +| S4 | Mover planes obsoletos de `docs/plan/` a `docs/_hist/` | Consolidación | ✅ | +| S5 | Mover docs técnicos duplicados (`docs/tecnica/`) a `docs/_hist/` | Consolidación | ✅ | +| S6 | Eliminar manifiesto vacío `docs/proyectos/P2604_proyecto_p2604.md` | Limpieza | ✅ | +| S7 | Corregir referencia a plan obsoleto en `run` | Fix | ✅ | +| S8 | Dejar de cargar `core/validador.rb` obsoleto en `run` | Limpieza | ✅ | +| S9 | Limpiar progreso duplicado en este plan | Doc | ✅ | +| S10 | Migrar `SubcomandoSalud` al namespace `ADN::` | Refactor | ⏳ | + +--- + +## Progreso + +``` +Fase 1: ██████████ 100% (T1-T3: 15 tests) +Fase 2: ██████░░░░ 67% (D1, D3 done) +Fase 3: ██████████ 100% (E1-E3: error handler) +Fase 4: ██████████ 100% (C1-C3: constants.rb) +Fase 5: ██████████ 100% (L1-L3: logger.rb) +Fase 6: ██████████ 100% (H1: HelpFormatter) +Fase 7: ██████████ 100% (DOC1-DOC3: docs/tecnica/) +Fase 8: ██████████ 100% (CI1-CI2: GitHub Actions) +Fase 9: ██████████ 100% (M1-M5: MSP CLI) +Fase 10: █████████░ 90% (S1-S9 done, S10 pendiente) +``` + +--- + +## Métricas Totales + +| Métrica | Valor | +| :--- | :--- | +| Tests pasando | 15 | +| Archivos creados | 12 | +| Archivos modificados | 8 | +| Archivos limpiados/movidos | 20+ | +| Fases completadas | 9/10 (90%) | +| Documentos técnicos | Consolidados en `adn/README.md` | + +--- + +## Próxima Acción + +**S10**: Migrar `SubcomandoSalud` al namespace `ADN::` y reescribir para consultar DB (DB-First) + +--- + +## Referencias + +- Punto de verdad: [`adn/README.md`](../../adn/README.md) +- ADN IA: [`05_ia.md`](../../adn/05_ia.md) +- Bitácoras: ID 1054-1056, 1073 +- Planes históricos movidos a: `docs/_hist/plan/`