#!/bin/bash # Script para enlazar la configuración de Claude desde este repositorio a ~/.claude # Esto permite sincronizar comandos, templates, includes, skills y agents entre máquinas set -e REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CLAUDE_DIR="$HOME/.claude" # Carpetas a enlazar (configuración compartible) FOLDERS=("skills" "agents" "commands") echo "=== Instalando configuración de Claude ===" echo "Repositorio: $REPO_DIR/.claude" echo "Destino: $CLAUDE_DIR" echo "" # Crear ~/.claude si no existe if [ ! -d "$CLAUDE_DIR" ]; then echo "Creando $CLAUDE_DIR..." mkdir -p "$CLAUDE_DIR" fi for folder in "${FOLDERS[@]}"; do SOURCE="$REPO_DIR/.claude/$folder" TARGET="$CLAUDE_DIR/$folder" # Verificar que la carpeta existe en el repo if [ ! -d "$SOURCE" ]; then echo "WARN: $SOURCE no existe, saltando..." continue fi # Si ya es un symlink correcto, saltar if [ -L "$TARGET" ] && [ "$(readlink "$TARGET")" = "$SOURCE" ]; then echo "OK: $folder ya está enlazado correctamente" continue fi # Si existe (archivo, carpeta o symlink incorrecto), hacer backup if [ -e "$TARGET" ] || [ -L "$TARGET" ]; then BACKUP="$TARGET.backup.$(date +%Y%m%d_%H%M%S)" echo "Backup: $TARGET -> $BACKUP" mv "$TARGET" "$BACKUP" fi # Crear symlink ln -s "$SOURCE" "$TARGET" echo "Enlazado: $folder -> $SOURCE" done # === Archivos de configuración === echo "" echo "=== Instalando archivos de configuración ===" # 1. Status Line Script STATUSLINE_SOURCE="$REPO_DIR/.claude/statusline.sh" STATUSLINE_TARGET="$CLAUDE_DIR/statusline.sh" if [ -f "$STATUSLINE_SOURCE" ]; then if [ -f "$STATUSLINE_TARGET" ]; then BACKUP="$STATUSLINE_TARGET.backup.$(date +%Y%m%d_%H%M%S)" echo "Backup: statusline.sh -> $BACKUP" mv "$STATUSLINE_TARGET" "$BACKUP" fi cp "$STATUSLINE_SOURCE" "$STATUSLINE_TARGET" chmod +x "$STATUSLINE_TARGET" echo "Copiado: statusline.sh (ejecutable)" else echo "WARN: statusline.sh no encontrado en el repo" fi # 2. Settings.json (enlace simbólico) SETTINGS_SOURCE="$REPO_DIR/.claude/settings.json" SETTINGS_TARGET="$CLAUDE_DIR/settings.json" if [ -f "$SETTINGS_SOURCE" ]; then # Si ya es un symlink correcto, saltar if [ -L "$SETTINGS_TARGET" ] && [ "$(readlink "$SETTINGS_TARGET")" = "$SETTINGS_SOURCE" ]; then echo "OK: settings.json ya está enlazado correctamente" else # Si existe (archivo o symlink incorrecto), hacer backup if [ -e "$SETTINGS_TARGET" ] || [ -L "$SETTINGS_TARGET" ]; then BACKUP="$SETTINGS_TARGET.backup.$(date +%Y%m%d_%H%M%S)" echo "Backup: settings.json -> $BACKUP" mv "$SETTINGS_TARGET" "$BACKUP" fi # Crear symlink ln -s "$SETTINGS_SOURCE" "$SETTINGS_TARGET" echo "Enlazado: settings.json -> $SETTINGS_SOURCE" fi else echo "WARN: settings.json no encontrado en el repo" fi # === Limpieza de configuración que no debe cambiar === echo "" echo "=== Limpiando configuración inmutable ===" # 1. Eliminar backups viejos de settings.json (más de 7 días) DELETED_BACKUPS=0 for backup in "$CLAUDE_DIR"/settings.json.backup.*; do [ -f "$backup" ] || continue if [ "$(find "$backup" -mtime +7 2>/dev/null)" ]; then rm -f "$backup" DELETED_BACKUPS=$((DELETED_BACKUPS + 1)) fi done [ "$DELETED_BACKUPS" -gt 0 ] && echo "Eliminados $DELETED_BACKUPS backups viejos de settings.json" # 2. Eliminar backups viejos de statusline.sh (más de 7 días) DELETED_SL=0 for backup in "$CLAUDE_DIR"/statusline.sh.backup.*; do [ -f "$backup" ] || continue if [ "$(find "$backup" -mtime +7 2>/dev/null)" ]; then rm -f "$backup" DELETED_SL=$((DELETED_SL + 1)) fi done [ "$DELETED_SL" -gt 0 ] && echo "Eliminados $DELETED_SL backups viejos de statusline.sh" # 3. Si settings.json es un symlink correcto, eliminar cualquier settings.json suelto # que pueda haber quedado (no el symlink en sí) if [ -L "$CLAUDE_DIR/settings.json" ] && [ "$(readlink "$CLAUDE_DIR/settings.json")" = "$REPO_DIR/.claude/settings.json" ]; then # Eliminar archivos sueltos que puedan sobreescribir el symlink for stale in "$CLAUDE_DIR"/settings.json.tmp "$CLAUDE_DIR"/settings.json.new; do if [ -f "$stale" ]; then rm -f "$stale" echo "Eliminado archivo temporal: $(basename "$stale")" fi done fi # 4. Resetear settings.local.json a vacío si existe con contenido # (este archivo es para overrides locales temporales, no debe acumular config) LOCAL_SETTINGS="$CLAUDE_DIR/settings.local.json" if [ -f "$LOCAL_SETTINGS" ] && [ -s "$LOCAL_SETTINGS" ]; then CONTENT=$(cat "$LOCAL_SETTINGS" 2>/dev/null) # Solo limpiar si tiene contenido real (no solo {} o vacío) if [ "$CONTENT" != "{}" ] && [ "$CONTENT" != "" ]; then echo "WARN: settings.local.json tenía contenido, reseteando a vacío" echo -n "" > "$LOCAL_SETTINGS" fi fi # 5. Asegurar que settings.json tiene los permisos de allow/deny correctos # Allow: editar .claude/ sin preguntar | Deny: nunca tocar .git/ REQUIRED_PERMISSIONS='{ "allow": [ "Edit(~/.claude/**)", "Write(~/.claude/**)", "Edit(.claude/**)", "Write(.claude/**)" ], "deny": [ "Edit(~/.claude/.git/**)", "Write(~/.claude/.git/**)", "Edit(.git/**)", "Write(.git/**)" ] }' SETTINGS_FILE="$REPO_DIR/.claude/settings.json" if [ -f "$SETTINGS_FILE" ] && command -v jq &>/dev/null; then CURRENT_PERMS=$(jq -c '.permissions // empty' "$SETTINGS_FILE" 2>/dev/null) EXPECTED_PERMS=$(echo "$REQUIRED_PERMISSIONS" | jq -c '.') if [ "$CURRENT_PERMS" != "$EXPECTED_PERMS" ]; then jq --argjson perms "$REQUIRED_PERMISSIONS" '.permissions = $perms' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp" \ && mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE" echo "Actualizado: permissions en settings.json (allow .claude/*, deny .git/*)" else echo "OK: permissions ya están correctos" fi else echo "WARN: jq no disponible, no se pudo verificar permissions" fi # 6. Asegurar que el settings.json del repo no tiene permisos de escritura para group/others chmod 644 "$REPO_DIR/.claude/settings.json" echo "Permisos de settings.json del repo: 644 (rw-r--r--)" echo "" echo "=== Instalación completada ===" echo "Tus comandos y configuración ahora están sincronizados con el repositorio." echo "" echo "Configuración instalada:" echo " • Skills, Agents y Commands enlazados simbólicamente" echo " • Status Line configurada con vibecoding setup" echo " • Settings.json enlazado (compartido entre repos)" echo " • Backups viejos limpiados (>7 días)" echo " • Archivos temporales de configuración eliminados" echo "" echo "Reinicia Claude Code para ver la nueva status line."