feat: añadir script bash para automatizar setup de Jupyter
Script setup-jupyter.sh que automatiza todo el proceso de inicialización: - Verifica estado actual (MCP, config, Jupyter, reglas) - Elimina instalación global de MCP si existe - Detecta puerto libre automáticamente - Crea run-jupyter-lab.sh, .mcp.json, CLAUDE.md - Instala dependencias con uv/pip - Devuelve STATUS para que el agente interprete el resultado
This commit is contained in:
Executable
+397
@@ -0,0 +1,397 @@
|
||||
#!/bin/bash
|
||||
# setup-jupyter.sh - Automatiza la configuración de Jupyter + MCP para Claude
|
||||
# Uso: ./setup-jupyter.sh [ruta-proyecto]
|
||||
# Generado para el skill /init-jupyter
|
||||
|
||||
set -e
|
||||
|
||||
# Colores para output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# FUNCIONES AUXILIARES
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
find_free_port() {
|
||||
for port in 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899; do
|
||||
if ! lsof -i:$port >/dev/null 2>&1; then
|
||||
echo $port
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo 8888
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 0: CAMBIAR AL DIRECTORIO DEL PROYECTO
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
RUTA="${1:-.}"
|
||||
cd "$RUTA" || { log_error "No se pudo acceder a: $RUTA"; exit 1; }
|
||||
PROJECT_PATH=$(pwd)
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " SETUP JUPYTER + MCP para Claude"
|
||||
echo " Proyecto: $PROJECT_PATH"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 1: VERIFICACIONES DE ESTADO
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Verificando estado actual..."
|
||||
|
||||
# Variables de estado
|
||||
MCP_LOCAL=false
|
||||
REPO_CONFIG=false
|
||||
JUPYTER_RUNNING=false
|
||||
RULES_OK=false
|
||||
GLOBAL_MCP=false
|
||||
CURRENT_PORT=""
|
||||
|
||||
# 1. MCP instalado localmente
|
||||
if [ -f .venv/bin/jupyter-mcp-server ]; then
|
||||
MCP_LOCAL=true
|
||||
log_ok "MCP instalado en .venv/bin/"
|
||||
else
|
||||
log_warn "MCP no instalado localmente"
|
||||
fi
|
||||
|
||||
# 2. Repo configurado (.mcp.json con jupyter)
|
||||
if [ -f .mcp.json ] && grep -q "jupyter" .mcp.json 2>/dev/null; then
|
||||
REPO_CONFIG=true
|
||||
log_ok "Repo configurado (.mcp.json tiene jupyter)"
|
||||
else
|
||||
log_warn "Repo no configurado para Jupyter"
|
||||
fi
|
||||
|
||||
# 3. Jupyter corriendo en este repo
|
||||
if pgrep -af "jupyter" 2>/dev/null | grep -q "$PROJECT_PATH"; then
|
||||
JUPYTER_RUNNING=true
|
||||
CURRENT_PORT=$(pgrep -af "jupyter" | grep "$PROJECT_PATH" | grep -oP 'port[= ]\K\d+' | head -1)
|
||||
[ -z "$CURRENT_PORT" ] && CURRENT_PORT=$(cat .jupyter-port 2>/dev/null || echo "desconocido")
|
||||
log_ok "Jupyter corriendo en puerto $CURRENT_PORT"
|
||||
else
|
||||
log_warn "Jupyter no está corriendo"
|
||||
fi
|
||||
|
||||
# 4. Reglas en CLAUDE.md
|
||||
if [ -f .claude/CLAUDE.md ] && grep -q "JUPYTER HABILITADO" .claude/CLAUDE.md 2>/dev/null; then
|
||||
RULES_OK=true
|
||||
log_ok "Reglas Jupyter en CLAUDE.md"
|
||||
else
|
||||
log_warn "Reglas Jupyter no configuradas"
|
||||
fi
|
||||
|
||||
# 5. Instalación global (problemática)
|
||||
if [ -f ~/.local/bin/jupyter-mcp-server ]; then
|
||||
GLOBAL_MCP=true
|
||||
log_warn "Existe instalación GLOBAL de jupyter-mcp-server (se eliminará)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# DECISIÓN: ¿Ya está todo configurado?
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
if $MCP_LOCAL && $REPO_CONFIG && $RULES_OK; then
|
||||
if $JUPYTER_RUNNING; then
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
log_ok "TODO LISTO - Jupyter configurado y corriendo en puerto $CURRENT_PORT"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "STATUS: READY"
|
||||
echo "PORT: $CURRENT_PORT"
|
||||
exit 0
|
||||
else
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
log_ok "CONFIGURADO - Solo falta iniciar Jupyter"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Ejecuta en otra terminal:"
|
||||
echo " cd $PROJECT_PATH && ./run-jupyter-lab.sh"
|
||||
echo ""
|
||||
echo "STATUS: CONFIGURED_NOT_RUNNING"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 2: ELIMINAR INSTALACIÓN GLOBAL SI EXISTE
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
if $GLOBAL_MCP; then
|
||||
log_info "Eliminando instalación global de jupyter-mcp-server..."
|
||||
uv tool uninstall jupyter-mcp-server 2>/dev/null || true
|
||||
pip uninstall -y jupyter-mcp-server 2>/dev/null || true
|
||||
rm -f ~/.local/bin/jupyter-mcp-server
|
||||
|
||||
if [ -f ~/.local/bin/jupyter-mcp-server ]; then
|
||||
log_error "No se pudo eliminar instalación global"
|
||||
else
|
||||
log_ok "Instalación global eliminada"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 3: DETECTAR PUERTO LIBRE
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
PUERTO=$(find_free_port)
|
||||
log_info "Puerto asignado: $PUERTO"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 4: CREAR ESTRUCTURA DE CARPETAS
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Creando estructura de carpetas..."
|
||||
mkdir -p .claude notebooks
|
||||
log_ok "Carpetas .claude/ y notebooks/ creadas"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 5: CREAR run-jupyter-lab.sh
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Creando run-jupyter-lab.sh..."
|
||||
|
||||
cat > run-jupyter-lab.sh << 'SCRIPT'
|
||||
#!/bin/bash
|
||||
# Jupyter Lab para colaboración Claude + Usuario
|
||||
# Generado por /init-jupyter
|
||||
# REQUIERE: jupyter-collaboration instalado para que funcione el MCP
|
||||
|
||||
# Autodetectar puerto libre
|
||||
find_free_port() {
|
||||
for port in 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899; do
|
||||
if ! lsof -i:$port >/dev/null 2>&1; then
|
||||
echo $port
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo 8888
|
||||
}
|
||||
|
||||
PORT=${1:-$(find_free_port)}
|
||||
|
||||
# Guardar puerto para que Claude lo lea
|
||||
echo $PORT > .jupyter-port
|
||||
|
||||
# Activar entorno si existe
|
||||
source .venv/bin/activate 2>/dev/null || true
|
||||
|
||||
# Verificar que jupyter-collaboration está instalado
|
||||
if ! python -c "import jupyter_collaboration" 2>/dev/null; then
|
||||
echo "ERROR: jupyter-collaboration no está instalado"
|
||||
echo "Instala con: uv add jupyter-collaboration"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
echo " Jupyter Lab + Colaboración iniciando en puerto $PORT"
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo " Abre: http://localhost:$PORT"
|
||||
echo ""
|
||||
echo " Claude se conectará al kernel cuando abras un notebook"
|
||||
echo " Colaboración en tiempo real ACTIVADA"
|
||||
echo " Usa Ctrl+C para detener"
|
||||
echo ""
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
|
||||
jupyter lab \
|
||||
--port=$PORT \
|
||||
--no-browser \
|
||||
--ServerApp.token='' \
|
||||
--ServerApp.password='' \
|
||||
--ServerApp.disable_check_xsrf=True \
|
||||
--ServerApp.allow_origin='*' \
|
||||
--ServerApp.root_dir="$(pwd)" \
|
||||
--YDocExtension.ystore_class='ypy_websocket.ystore.TempFileYStore' \
|
||||
--collaborative
|
||||
SCRIPT
|
||||
|
||||
chmod +x run-jupyter-lab.sh
|
||||
log_ok "run-jupyter-lab.sh creado"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 6: CREAR/ACTUALIZAR .mcp.json
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Configurando .mcp.json..."
|
||||
|
||||
# Crear config temporal
|
||||
cat > /tmp/jupyter-mcp.json << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"jupyter": {
|
||||
"command": "${PROJECT_PATH}/.venv/bin/jupyter-mcp-server",
|
||||
"args": [
|
||||
"--runtime-url", "http://localhost:${PUERTO}",
|
||||
"--start-new-runtime", "false"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Merge o crear
|
||||
if [ -f .mcp.json ]; then
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq -s '.[0] * .[1] | .mcpServers = (.[0].mcpServers // {}) * (.[1].mcpServers // {})' \
|
||||
.mcp.json /tmp/jupyter-mcp.json > .mcp.json.tmp
|
||||
mv .mcp.json.tmp .mcp.json
|
||||
log_ok ".mcp.json actualizado (merge)"
|
||||
else
|
||||
log_warn "jq no disponible, sobrescribiendo .mcp.json"
|
||||
mv /tmp/jupyter-mcp.json .mcp.json
|
||||
fi
|
||||
else
|
||||
mv /tmp/jupyter-mcp.json .mcp.json
|
||||
log_ok ".mcp.json creado"
|
||||
fi
|
||||
|
||||
rm -f /tmp/jupyter-mcp.json
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 7: ACTUALIZAR .claude/CLAUDE.md
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Configurando reglas en .claude/CLAUDE.md..."
|
||||
|
||||
JUPYTER_RULES='# JUPYTER HABILITADO EN ESTE REPO
|
||||
|
||||
Este repositorio está configurado para exploración de datos con Jupyter + Claude.
|
||||
|
||||
## Estado del entorno
|
||||
- **Lanzador**: `./run-jupyter-lab.sh`
|
||||
- **Puerto config**: ver `.jupyter-port` o `.mcp.json`
|
||||
- **MCP**: jupyter-mcp-server configurado
|
||||
|
||||
## Reglas OBLIGATORIAS para Claude
|
||||
|
||||
### 1. SIEMPRE usar MCP jupyter para ejecutar código Python
|
||||
- Las ejecuciones se ven en tiempo real en Jupyter Lab del usuario
|
||||
- Compartimos variables y estado del kernel
|
||||
- **NUNCA usar bash para ejecutar Python en este repo**
|
||||
|
||||
### 2. Verificar Jupyter activo ANTES de ejecutar
|
||||
```bash
|
||||
pgrep -af "jupyter" | grep "$(pwd)" || cat .jupyter-port 2>/dev/null
|
||||
```
|
||||
- Si no está activo → pedir al usuario: "Ejecuta `./run-jupyter-lab.sh` en otra terminal"
|
||||
|
||||
### 3. Gestión de notebooks
|
||||
- Si un notebook tiene >50 celdas → crear uno nuevo
|
||||
- Nombrar descriptivamente: `01_exploracion.ipynb`, `02_limpieza.ipynb`
|
||||
- Mantener notebooks enfocados en una tarea
|
||||
|
||||
### 4. Antes de código pesado
|
||||
- Avisar al usuario
|
||||
- Usar `%%time` o `tqdm` para progreso
|
||||
|
||||
---
|
||||
|
||||
'
|
||||
|
||||
if [ -f .claude/CLAUDE.md ]; then
|
||||
if ! grep -q "JUPYTER HABILITADO" .claude/CLAUDE.md; then
|
||||
# Prepend
|
||||
echo "$JUPYTER_RULES" > .claude/CLAUDE.md.tmp
|
||||
cat .claude/CLAUDE.md >> .claude/CLAUDE.md.tmp
|
||||
mv .claude/CLAUDE.md.tmp .claude/CLAUDE.md
|
||||
log_ok "Reglas añadidas al principio de CLAUDE.md"
|
||||
else
|
||||
log_ok "Reglas ya existían en CLAUDE.md"
|
||||
fi
|
||||
else
|
||||
echo "$JUPYTER_RULES" > .claude/CLAUDE.md
|
||||
log_ok "CLAUDE.md creado con reglas"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PASO 8: INICIALIZAR ENTORNO PYTHON E INSTALAR DEPENDENCIAS
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
log_info "Configurando entorno Python..."
|
||||
|
||||
# Crear venv si no existe
|
||||
if [ ! -d .venv ]; then
|
||||
log_info "Creando venv..."
|
||||
uv venv 2>/dev/null || python -m venv .venv
|
||||
fi
|
||||
|
||||
# Activar venv
|
||||
source .venv/bin/activate 2>/dev/null || true
|
||||
|
||||
# Instalar dependencias
|
||||
log_info "Instalando dependencias (jupyter, mcp, colaboración)..."
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
# Inicializar pyproject.toml si no existe
|
||||
[ ! -f pyproject.toml ] && uv init 2>/dev/null || true
|
||||
uv add jupyter jupyterlab jupyter-collaboration jupyter-mcp-server pandas numpy matplotlib 2>/dev/null || \
|
||||
pip install jupyter jupyterlab jupyter-collaboration jupyter-mcp-server pandas numpy matplotlib
|
||||
else
|
||||
pip install jupyter jupyterlab jupyter-collaboration jupyter-mcp-server pandas numpy matplotlib
|
||||
fi
|
||||
|
||||
# Verificar instalación
|
||||
echo ""
|
||||
if [ -f .venv/bin/jupyter-mcp-server ]; then
|
||||
log_ok "jupyter-mcp-server instalado en venv local"
|
||||
else
|
||||
log_error "jupyter-mcp-server NO instalado"
|
||||
fi
|
||||
|
||||
if python -c "import jupyter_collaboration" 2>/dev/null; then
|
||||
log_ok "jupyter-collaboration instalado"
|
||||
else
|
||||
log_warn "jupyter-collaboration no instalado"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# RESUMEN FINAL
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " CONFIGURACIÓN COMPLETADA"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo " Proyecto: $PROJECT_PATH"
|
||||
echo " Puerto: $PUERTO"
|
||||
echo ""
|
||||
echo " Archivos creados/actualizados:"
|
||||
echo " ✓ run-jupyter-lab.sh"
|
||||
echo " ✓ .mcp.json"
|
||||
echo " ✓ .claude/CLAUDE.md"
|
||||
echo " ✓ .venv/bin/jupyter-mcp-server"
|
||||
echo ""
|
||||
echo " ┌─────────────────────────────────────────────────────────┐"
|
||||
echo " │ PASOS SIGUIENTES: │"
|
||||
echo " │ │"
|
||||
echo " │ 1. SALIR de Claude Code: /exit o Ctrl+C │"
|
||||
echo " │ (necesario para cargar el nuevo MCP) │"
|
||||
echo " │ │"
|
||||
echo " │ 2. En OTRA terminal: │"
|
||||
echo " │ cd $PROJECT_PATH && ./run-jupyter-lab.sh │"
|
||||
echo " │ │"
|
||||
echo " │ 3. Volver a entrar a Claude: │"
|
||||
echo " │ cd $PROJECT_PATH && claude │"
|
||||
echo " │ │"
|
||||
echo " │ 4. Abrir en navegador: http://localhost:$PUERTO │"
|
||||
echo " └─────────────────────────────────────────────────────────┘"
|
||||
echo ""
|
||||
echo "STATUS: CONFIGURED"
|
||||
echo "PORT: $PUERTO"
|
||||
Reference in New Issue
Block a user