JARVIS/verde/verde-launcher.sh
sito 1e3e5ca20d carril verde (Hermes Agent): documentacion, panel, voz local y RAG
Rama JARVIS-GREEN, independiente de master (el nucleo naranja queda intacto).

- README propio del carril verde con diagrama de arquitectura y capturas del panel.
- verde/: arranque, panel web, puente de voz (escucha local con faster-whisper +
  habla con la voz del naranja), pruebas (07 voz, 08 escucha), config y notas.
- Integracion RAG: nucleo/saber/busca_cli.py + skill buscar-en-apuntes, para que
  el agente consulte el mismo indice que el nucleo.
- Todo local (127.0.0.1); sin datos personales (rutas y modelo de GPU scrubeados).
2026-08-18 11:26:42 +02:00

150 lines
6.1 KiB
Bash
Executable file

#!/usr/bin/env bash
# JARVIS verde — el banco de pruebas con Hermes Agent.
#
# verde-launcher.sh abre el TUI de Hermes en verde fosforo
# verde-launcher.sh --status que corre y cuanta VRAM, sin arrancar nada
# verde-launcher.sh --stop cerrar y soltar la VRAM
# verde-launcher.sh --sin-color igual pero sin tocar la paleta
#
# ── El verde no es decoracion ──────────────────────────────────────────────
#
# Hay tres JARVIS en esta maquina y se distinguen por color, como ya hacia el
# README: cian el de Newelle (congelado), naranja el nucleo (en desarrollo),
# verde este. Cuando tienes dos terminales abiertos a las tres de la manana,
# el color es lo unico que te dice cual estas tocando.
#
# Hermes NO tiene tema para su TUI — mirado en hermes_cli/config_defaults.py,
# la unica clave "theme" que existe es la del panel web. Asi que el color lo
# pone la terminal, con secuencias OSC:
#
# OSC 10 primer plano OSC 11 fondo OSC 12 cursor
#
# Se hace asi y no editando tu perfil de terminal a proposito: esto pinta SOLO
# esta ventana y solo mientras dura la sesion. Tu perfil por defecto y el del
# naranja se quedan como estan. Al salir se restaura con OSC 110/111/112.
set -uo pipefail
AQUI=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)
RAIZ=$(cd -P "$AQUI/.." && pwd)
# Fosforo verde. Los mismos tonos que jarvis-verde.svg, para que el icono y la
# pantalla sean el mismo color.
VERDE=${JARVIS_VERDE_TINTA:-#00ff41}
FONDO=${JARVIS_VERDE_FONDO:-#04120a}
HERMES=${HERMES_BIN:-$HOME/.local/bin/hermes}
OLLAMA_URL=${OLLAMA_URL:-http://127.0.0.1:11434}
# ── la paleta ──────────────────────────────────────────────────────────────
pinta_verde() {
[ -t 1 ] || return 0 # sin terminal, nada que pintar
printf '\033]10;%s\007' "$VERDE"
printf '\033]11;%s\007' "$FONDO"
printf '\033]12;%s\007' "$VERDE"
}
restaura() {
[ -t 1 ] || return 0
printf '\033]110\007\033]111\007\033]112\007'
}
# ── comprobaciones que no arrancan nada ────────────────────────────────────
estado() {
printf 'JARVIS verde\n\n'
printf ' hermes '
if [ -x "$HERMES" ]; then printf 'instalado en %s\n' "$HERMES"
else printf 'NO instalado\n'; fi
printf ' ollama '
if curl -fsS --max-time 2 "$OLLAMA_URL/api/tags" >/dev/null 2>&1; then
printf 'en pie (%s)\n' "$OLLAMA_URL"
else
printf 'NO responde en %s\n' "$OLLAMA_URL"
fi
printf ' modelo '
# El modelo se LEE de la configuracion, no se escribe aqui. El lanzador del
# naranja llevaba el nombre a mano y se quedo desfasado: precargaba
# qwen3.5:4b mientras la app usaba qwen3.5:4b-jarvis, o sea 2941 MiB del que
# no era, ollama tenia que descargar y recargar, y de paso dejaba la tarjeta
# sin sitio para whisper. Aqui pasaria igual: este fichero decia
# qwen3.5:4b-jarvis y el carril va con qwen3.5:4b-verde.
MODELO=$(python3 -c "
import yaml
print(yaml.safe_load(open('$HOME/.hermes/config.yaml'))['model'].get('default',''))
" 2>/dev/null)
if [ -z "$MODELO" ]; then
printf 'no pude leer model.default de ~/.hermes/config.yaml\n'
elif curl -fsS --max-time 2 "$OLLAMA_URL/api/tags" 2>/dev/null \
| grep -q "$MODELO"; then
printf '%s disponible\n' "$MODELO"
else
printf '%s NO esta (lo crea verde/arrancar.sh)\n' "$MODELO"
fi
printf ' voz '
if [ -x "$AQUI/voz-verde.sh" ] && [ -x "$RAIZ/config/jarvis-piper.sh" ]; then
printf 'jarvis-piper.sh, la misma que el naranja\n'
else
printf 'falta el adaptador o jarvis-piper.sh\n'
fi
printf ' VRAM '
if command -v nvidia-smi >/dev/null 2>&1; then
nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader
else
printf '(sin nvidia-smi)\n'
fi
}
parar() {
# El gateway solo existe si algun dia se configura un canal de mensajeria.
if [ -x "$HERMES" ]; then "$HERMES" gateway stop 2>/dev/null || true; fi
pkill -f 'hermes' 2>/dev/null || true
printf 'parado. La VRAM la suelta ollama solo cuando el modelo caduca.\n'
}
# ── main ───────────────────────────────────────────────────────────────────
COLOR=si
case "${1:-}" in
--status|--estado) estado; exit 0 ;;
--stop|--parar) parar; exit 0 ;;
--sin-color) COLOR=no; shift ;;
esac
if [ ! -x "$HERMES" ]; then
printf 'No encuentro hermes en %s\n' "$HERMES" >&2
printf 'Instalalo con: %s/instalar.sh\n' "$AQUI" >&2
exit 1
fi
# El cerebro es local: si ollama no esta en pie, Hermes no tiene con que
# pensar. Se avisa antes en vez de dejar que falle en la primera frase.
if ! curl -fsS --max-time 2 "$OLLAMA_URL/api/tags" >/dev/null 2>&1; then
printf 'Aviso: ollama no responde en %s.\n' "$OLLAMA_URL" >&2
printf 'El cerebro del verde es local; arrancalo con: systemctl start ollama\n' >&2
fi
if [ "$COLOR" = si ]; then
pinta_verde
trap restaura EXIT INT TERM
fi
# ── El cd NO basta: hay que decirselo a Hermes ─────────────────────────────
#
# Este `cd` estaba solo, y no servia de nada. Hermes RESTAURA el directorio de
# trabajo que tenga apuntado en la sesion y se salta aquel desde el que lo
# lanzas. El sintoma no parece un fallo de rutas: se le pide "lee
# verde/README.md y resumelo" y contesta un resumen impecable de OTRO fichero
# —$HOME/README.md, que resulta ser el de Gitleaks— sin un solo error por
# ningun lado. Parece el modelo alucinando y es el directorio.
#
# --in DIR entra en el directorio Y se salta la restauracion; es la bandera que
# existe justo para esto. El cd se queda porque las comprobaciones de arriba y
# los ficheros de contexto (AGENTS.md, cwd files) se leen antes.
cd "$RAIZ"
exec "$HERMES" --in "$RAIZ" "$@"