diff --git a/README.md b/README.md
index 9f3277e..34020df 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
# MRDevs Tools
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
## 📋 Descripción
@@ -339,6 +339,13 @@ El script proporciona una instalación especializada para cada plataforma:
- En macOS: Utiliza Homebrew para instalación
- En FreeBSD: Configuración manual con AppImage (no hay soporte oficial)
+Características del instalador:
+- Obtiene automáticamente la última versión disponible desde GitHub
+- Solicita permisos de administrador cuando son necesarios
+- Utiliza interfaz gráfica para confirmación y línea de comandos para instalación
+- Limpia archivos de configuración residuales durante la desinstalación
+- Proporciona información detallada sobre las características de Zettlr
+
### Herramientas para Control de Versiones
MRDevs Tools incluye scripts para simplificar la instalación de CLIs para diferentes plataformas Git:
diff --git a/bin/bootstrap.sh b/bin/bootstrap.sh
index 705fd8f..e17a5bd 100755
--- a/bin/bootstrap.sh
+++ b/bin/bootstrap.sh
@@ -149,11 +149,23 @@ install() {
os_pkgs_install $SQLITE_PACKAGE
fi
- # Install python from OS Packages
- command_installed $PYTHON_PACKAGE
+ # Install full Python package even if basic Python is already installed
+ command_installed python3-full
if [ $? -ne 0 ]
then
+ # Si python3-full no está instalado, instalarlo
python3_install
+ else
+ # Si ya está python3 básico pero queremos asegurar que python3-full esté instalado
+ command_installed $PYTHON_PACKAGE
+ if [ $? -eq 0 ]
+ then
+ echo "Asegurando instalación completa de Python..."
+ if [ -f /etc/debian_version ] || [ -f /etc/os-release ]; then
+ apt update
+ apt install -y python3-full
+ fi
+ fi
fi
# Verificar si pip está instalado, instalarlo si es necesario
@@ -163,6 +175,13 @@ install() {
pip_install
fi
+ # Verificar si pipx está instalado, instalarlo si es necesario
+ command_installed pipx
+ if [ $? -ne 0 ]
+ then
+ pipx_install
+ fi
+
# Install mozilla sops from OS Packages
command_installed $SOPS_PACKAGE
if [ $? -ne 0 ]
diff --git a/bin/cocomo.py b/bin/cocomo.py
index f2120e7..5af3305 100755
--- a/bin/cocomo.py
+++ b/bin/cocomo.py
@@ -34,7 +34,7 @@ SHOW_RESULTS = True
# Directorio base del proyecto
BASE_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CONFIG_DIR = BASE_DIR / 'bin' / 'config'
-RATES_DIR = CONFIG_DIR / 'rates' # Ubicación para archivos de tarifas
+RATES_DIR = BASE_DIR / 'data' / 'rates' # Ubicación para archivos de tarifas
# Constantes para el modelo COCOMO básico
COCOMO_MODELS = {
@@ -210,7 +210,8 @@ def estimate_cocomo(loc, model_type='organic', cost_per_pm=5000, programmer_type
# Redondear valores para presentación
effort_pm = round(effort_pm, 2)
dev_time = round(dev_time, 2)
- avg_staff = round(avg_staff, 2)
+ # Redondear personal promedio al entero próximo (ceil)
+ avg_staff = ceil(avg_staff)
hourly_rate = round(hourly_rate, 2)
total_cost = round(total_cost, 2)
diff --git a/bin/config/rates/backend.rate b/bin/config/rates/backend.rate
deleted file mode 100644
index c351fec..0000000
--- a/bin/config/rates/backend.rate
+++ /dev/null
@@ -1 +0,0 @@
-57.73
\ No newline at end of file
diff --git a/bin/config/rates/bash.rate b/bin/config/rates/bash.rate
deleted file mode 100644
index dec8b77..0000000
--- a/bin/config/rates/bash.rate
+++ /dev/null
@@ -1 +0,0 @@
-23.64
\ No newline at end of file
diff --git a/bin/config/rates/cloud.rate b/bin/config/rates/cloud.rate
deleted file mode 100644
index ba00533..0000000
--- a/bin/config/rates/cloud.rate
+++ /dev/null
@@ -1 +0,0 @@
-51.00
\ No newline at end of file
diff --git a/bin/config/rates/data.rate b/bin/config/rates/data.rate
deleted file mode 100644
index bc0becf..0000000
--- a/bin/config/rates/data.rate
+++ /dev/null
@@ -1 +0,0 @@
-56.81
\ No newline at end of file
diff --git a/bin/config/rates/devops.rate b/bin/config/rates/devops.rate
deleted file mode 100644
index 129beeb..0000000
--- a/bin/config/rates/devops.rate
+++ /dev/null
@@ -1 +0,0 @@
-59.11
\ No newline at end of file
diff --git a/bin/config/rates/dotnet.rate b/bin/config/rates/dotnet.rate
deleted file mode 100644
index 9a43705..0000000
--- a/bin/config/rates/dotnet.rate
+++ /dev/null
@@ -1 +0,0 @@
-49.00
\ No newline at end of file
diff --git a/bin/config/rates/frontend.rate b/bin/config/rates/frontend.rate
deleted file mode 100644
index 83185d0..0000000
--- a/bin/config/rates/frontend.rate
+++ /dev/null
@@ -1 +0,0 @@
-41.00
\ No newline at end of file
diff --git a/bin/config/rates/fullstack.rate b/bin/config/rates/fullstack.rate
deleted file mode 100644
index e92548e..0000000
--- a/bin/config/rates/fullstack.rate
+++ /dev/null
@@ -1 +0,0 @@
-88.66
\ No newline at end of file
diff --git a/bin/config/rates/java.rate b/bin/config/rates/java.rate
deleted file mode 100644
index 9a43705..0000000
--- a/bin/config/rates/java.rate
+++ /dev/null
@@ -1 +0,0 @@
-49.00
\ No newline at end of file
diff --git a/bin/config/rates/ml.rate b/bin/config/rates/ml.rate
deleted file mode 100644
index 9a43705..0000000
--- a/bin/config/rates/ml.rate
+++ /dev/null
@@ -1 +0,0 @@
-49.00
\ No newline at end of file
diff --git a/bin/config/rates/mobile.rate b/bin/config/rates/mobile.rate
deleted file mode 100644
index afc2c6d..0000000
--- a/bin/config/rates/mobile.rate
+++ /dev/null
@@ -1 +0,0 @@
-47.00
\ No newline at end of file
diff --git a/bin/config/rates/odoo.rate b/bin/config/rates/odoo.rate
deleted file mode 100644
index 6e395fa..0000000
--- a/bin/config/rates/odoo.rate
+++ /dev/null
@@ -1 +0,0 @@
-20.00
\ No newline at end of file
diff --git a/bin/config/rates/php.rate b/bin/config/rates/php.rate
deleted file mode 100644
index 9a43705..0000000
--- a/bin/config/rates/php.rate
+++ /dev/null
@@ -1 +0,0 @@
-49.00
\ No newline at end of file
diff --git a/bin/config/rates/python.rate b/bin/config/rates/python.rate
deleted file mode 100644
index 9a43705..0000000
--- a/bin/config/rates/python.rate
+++ /dev/null
@@ -1 +0,0 @@
-49.00
\ No newline at end of file
diff --git a/bin/config/rates/ruby.rate b/bin/config/rates/ruby.rate
deleted file mode 100644
index 628c8f1..0000000
--- a/bin/config/rates/ruby.rate
+++ /dev/null
@@ -1 +0,0 @@
-31.00
\ No newline at end of file
diff --git a/bin/fix_haos_paths.sh b/bin/fix_haos_paths.sh
deleted file mode 100755
index aed83ae..0000000
--- a/bin/fix_haos_paths.sh
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/bin/bash
-#Script : fix_haos_paths.sh
-#Apps : MRDEVS TOOLS
-#Description : Corrige rutas en contenedores HAOS existentes y crea estructura correcta
-#Author : Cortana Rosero One
-#Created : 2025/04/02 12:00:00
-#Modified : 2025/04/02 12:00:00
-#Version : 1.0.0
-#==============================================================================
-# Derechos de Autor [2025] [Mauro Rosero P. ]
-#==============================================================================
-# Este programa es software libre: usted puede redistribuirlo y/o modificarlo
-# bajo los términos de la Licencia Pública Affero General de GNU tal como
-# lo publica la Free Software Foundation, ya sea la versión 3 de la licencia,
-# o (a su elección) cualquier versión posterior.
-#
-# Este programa se distribuye con la esperanza de que sea útil,
-# pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
-# COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la
-# Licencia Pública Affero General de GNU para obtener más detalles.
-#
-# Debería haber recibido una copia de la Licencia Pública Affero General
-# junto con este programa. Si no la recibió, consulte .
-# [Generated] Created by Claude Code (claude-3-7-sonnet-20250219)
-
-echo "=== Corrigiendo rutas de Home Assistant ==="
-
-# Configuración de contenedores
-HA_CORE_CONTAINER_NAME="homeassistant"
-HA_OS_CONTAINER_NAME="haos"
-
-# Asegurar que estamos en un directorio de proyecto
-if [[ ! "$PWD" == *"/projects/"* ]]; then
- echo "ADVERTENCIA: No parece estar en un directorio de proyecto."
- echo "Este script debe ejecutarse desde la carpeta del proyecto (ej: /home/mrosero/devs/projects/ha-home)"
- read -p "¿Desea continuar de todos modos? (s/n): " CONTINUE
- if [[ ! "$CONTINUE" =~ ^[Ss]$ ]]; then
- echo "Operación cancelada."
- exit 1
- fi
-fi
-
-# Crear estructura de directorios correcta
-echo "Creando estructura de directorios correcta en $PWD/ha"
-mkdir -p "$PWD/ha/config" "$PWD/ha/media" "$PWD/ha/ssl" "$PWD/ha/share"
-chmod -R 755 "$PWD/ha"
-
-# Verificar y detener contenedores si están ejecutándose
-for CONTAINER in $HA_CORE_CONTAINER_NAME $HA_OS_CONTAINER_NAME; do
- if podman container exists $CONTAINER; then
- echo "Deteniendo contenedor $CONTAINER..."
- podman stop $CONTAINER
-
- echo "Eliminando contenedor $CONTAINER (los datos persistirán)..."
- podman rm $CONTAINER
- fi
-done
-
-# Verificar si existe la estructura antigua
-OLD_PATH="/home/mrosero/devs/homeassistant"
-if [ -d "$OLD_PATH" ]; then
- echo "Se encontró estructura antigua en $OLD_PATH"
-
- # Migrar datos si es necesario
- if [ -d "$OLD_PATH/config" ] && [ "$(ls -A "$OLD_PATH/config" 2>/dev/null)" ]; then
- echo "Migrando datos de configuración..."
- cp -r "$OLD_PATH/config/"* "$PWD/ha/config/"
- fi
-
- if [ -d "$OLD_PATH/media" ] && [ "$(ls -A "$OLD_PATH/media" 2>/dev/null)" ]; then
- echo "Migrando datos de media..."
- cp -r "$OLD_PATH/media/"* "$PWD/ha/media/"
- fi
-
- if [ -d "$OLD_PATH/ssl" ] && [ "$(ls -A "$OLD_PATH/ssl" 2>/dev/null)" ]; then
- echo "Migrando certificados SSL..."
- cp -r "$OLD_PATH/ssl/"* "$PWD/ha/ssl/"
- fi
-
- if [ -d "$OLD_PATH/share" ] && [ "$(ls -A "$OLD_PATH/share" 2>/dev/null)" ]; then
- echo "Migrando datos compartidos..."
- cp -r "$OLD_PATH/share/"* "$PWD/ha/share/"
- fi
-
- echo "Respaldando estructura antigua a ${OLD_PATH}_backup..."
- mv "$OLD_PATH" "${OLD_PATH}_backup"
-fi
-
-echo "=== Operación completada ==="
-echo "Ahora puede iniciar Home Assistant con:"
-echo "../../bin/haos.sh start"
\ No newline at end of file
diff --git a/bin/lib/bootstrap.lib b/bin/lib/bootstrap.lib
index e1287c9..857bb17 100755
--- a/bin/lib/bootstrap.lib
+++ b/bin/lib/bootstrap.lib
@@ -104,7 +104,7 @@ function python3_install() {
elif [ -f /etc/debian_version ] || [ -f /etc/os-release ]; then
# En sistemas Debian y derivados, instalamos o actualizamos Python a través de apt
apt update
- apt install -y python3
+ apt install -y python3-full
elif [ -f /etc/redhat-release ]; then
# En sistemas Red Hat, instalamos o actualizamos Python a través de yum
dnf install -y python3
@@ -142,7 +142,7 @@ function python3_update() {
elif [ -f /etc/debian_version ] || [ -f /etc/os-release ]; then
# En sistemas Debian y derivados
apt update
- apt install --only-upgrade -y python3
+ apt install --only-upgrade -y python3-full
elif [ -f /etc/redhat-release ]; then
# En sistemas Red Hat
dnf upgrade -y python3
@@ -190,6 +190,30 @@ function pip_install() {
}
+# Install pipx package
+function pipx_install() {
+ echo "Instalando pipx..."
+
+ # Verificar si pip está instalado
+ command_installed pip3
+ if [ $? -ne 0 ]; then
+ # Si pip no está instalado, llamamos a la función de instalación
+ pip_install
+ fi
+
+ if [ "$(uname)" == "Darwin" ]; then
+ # En macOS, instalamos pipx a través de Homebrew
+ brew install pipx
+ pipx ensurepath
+ else
+ # En otros sistemas, instalamos pipx a través de pip
+ python3 -m pip install --user pipx
+ python3 -m pipx ensurepath
+ fi
+
+ echo "pipx instalado correctamente."
+}
+
# Update pip package
function pip_update() {
@@ -236,6 +260,31 @@ function pip_update() {
}
+# Update pipx package
+function pipx_update() {
+ echo "Actualizando pipx..."
+
+ # Verificar si pipx está instalado
+ command_installed pipx
+ if [ $? -ne 0 ]; then
+ # Si pipx no está instalado, llamamos a la función de instalación
+ pipx_install
+ return $?
+ fi
+
+ # Actualizar pipx según el sistema operativo
+ if [ "$(uname)" == "Darwin" ]; then
+ # En macOS, actualizamos pipx a través de Homebrew
+ brew upgrade pipx
+ else
+ # En otros sistemas, actualizamos pipx a través de pip
+ python3 -m pip install --user --upgrade pipx
+ fi
+
+ echo "pipx actualizado correctamente."
+ return 0
+}
+
# Install mozilla sops package on os system supported
function sops_install() {
diff --git a/bin/path_add.sh b/bin/path_add.sh
deleted file mode 100755
index 989c975..0000000
--- a/bin/path_add.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-#Script : path_add.sh
-#Apps : MRDEVS TOOLS
-#Description : Add bin directory to PATH (non-persistent)
-#Author : Cortana Rosero One
-#Generated : Created by Claude Code (claude-3-7-sonnet-20250219)
-#Created : 2025/04/01 21:00:00
-#Modified : 2025/04/01 21:00:00
-#Version : 1.3.1
-#Use Notes : Source this script to add bin directory to PATH
-#==============================================================================
-# Derechos de Autor 2025 Mauro Rosero P.
-#==============================================================================
-# Este programa es software libre: usted puede redistribuirlo y/o modificarlo
-# bajo los términos de la Licencia Pública Affero General de GNU tal como
-# lo publica la Free Software Foundation, ya sea la versión 3 de la licencia,
-# o (a su elección) cualquier versión posterior.
-#
-# Este programa se distribuye con la esperanza de que sea útil,
-# pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
-# COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la
-# Licencia Pública Affero General de GNU para obtener más detalles.
-#
-# Debería haber recibido una copia de la Licencia Pública Affero General
-# junto con este programa. Si no la recibió, consulte .
-
-# Determinar la ruta base de la plataforma de desarrollo
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-DEVSPATH=$(cat "$SCRIPT_DIR/config/devspath.dat")
-BIN_DIR="$HOME/$DEVSPATH/bin"
-
-# Función para verificar si una ruta ya está en el PATH
-function path_contains() {
- local check_path="$1"
- echo "$PATH" | grep -q -E "(^|:)$check_path(:|$)"
- return $?
-}
-
-# Función para agregar la ruta al PATH
-function add_to_path() {
- local bin_path="$1"
-
- if ! path_contains "$bin_path"; then
- export PATH="$bin_path:$PATH"
- echo "✅ Ruta '$bin_path' agregada al PATH"
- else
- echo "ℹ️ La ruta '$bin_path' ya está en el PATH"
- fi
-}
-
-# Agregar la ruta bin al PATH
-add_to_path "$BIN_DIR"
-
-echo "✨ Los comandos de desarrollo están disponibles en esta sesión"
-echo "💡 Uso: source ${BIN_DIR}/path_add.sh"
\ No newline at end of file
diff --git a/bin/rate_update.py b/bin/rate_update.py
index 59f19f0..2305b6e 100755
--- a/bin/rate_update.py
+++ b/bin/rate_update.py
@@ -85,7 +85,7 @@ def check_install_pycountry():
# Directorio base del proyecto
BASE_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CONFIG_DIR = BASE_DIR / 'bin' / 'config'
-RATES_DIR = CONFIG_DIR / 'rates' # Nueva ubicación para archivos de tarifas
+RATES_DIR = BASE_DIR / 'data' / 'rates' # Nueva ubicación para archivos de tarifas
# Archivos de configuración para la API de Perplexity
MODEL_CONFIG_FILE = CONFIG_DIR / 'rate_model.ai'
@@ -157,12 +157,20 @@ def get_perplexity_api_key():
# Si seguimos sin tener API key, mostrar error y salir
if not api_key:
logger.error("No se encontró la clave API de Perplexity.")
- logger.error("Opciones para configurarla:")
+ logger.error("Se usarán valores predeterminados para las tarifas.")
+ logger.error("Para obtener tarifas más precisas, configure la API key de Perplexity:")
logger.error("1. Establecer la variable de entorno PERPLEXITY_API_KEY")
logger.error("2. Crear un archivo ~/.perplexity/api_key con la clave")
logger.error("3. Crear un archivo ~/.config/perplexity/api_key con la clave")
logger.error("4. Crear un archivo bin/config/perplexity_api_key en el directorio del proyecto")
- sys.exit(1)
+
+ if SHOW_RESULTS:
+ print("\nADVERTENCIA: No se encontró la clave API de Perplexity.")
+ print("Se usarán valores predeterminados para las tarifas.")
+ print("Para obtener tarifas más precisas, configure la API key visitando:")
+ print("https://docs.perplexity.ai/docs/getting-started")
+
+ return None
# Validar formato básico de la API key
if not api_key.startswith('pplx-'):
@@ -463,10 +471,8 @@ def update_single_rate(programmer_type):
# Verificar disponibilidad de la API
api_available = True
- try:
- # Intentar obtener la clave API (si falla, saltará una excepción)
- get_perplexity_api_key()
- except:
+ api_key = get_perplexity_api_key()
+ if api_key is None:
api_available = False
logger.warning("API de Perplexity no disponible. Se usarán valores predeterminados.")
@@ -666,10 +672,8 @@ def update_rate_files(force_update=False):
# Verificar disponibilidad de la API
api_available = True
- try:
- # Intentar obtener la clave API (si falla, saltará una excepción)
- get_perplexity_api_key()
- except:
+ api_key = get_perplexity_api_key()
+ if api_key is None:
api_available = False
logger.warning("API de Perplexity no disponible. Se usarán valores predeterminados.")
diff --git a/bin/update.sh b/bin/update.sh
index f2c209d..2827d83 100755
--- a/bin/update.sh
+++ b/bin/update.sh
@@ -100,7 +100,7 @@ update_python_and_pip() {
elif [ -f /etc/debian_version ] || [ -f /etc/os-release ]; then
# En sistemas Debian y derivados
apt update
- apt install --only-upgrade -y python3
+ apt install --only-upgrade -y python3-full
elif [ -f /etc/redhat-release ]; then
# En sistemas Red Hat
dnf upgrade -y python3
@@ -156,10 +156,25 @@ update_python_and_pip() {
echo -e "\n${head_info}: Actualizando Python y pip..."
- # Update Python
+ # Update Python - asegurándonos de que python3-full esté instalado
+ command_installed python3-full
+ PYTHON_FULL_INSTALLED=$?
+
command_installed python3
- if [ $? -eq 0 ]; then
+ PYTHON_BASIC_INSTALLED=$?
+
+ if [ $PYTHON_FULL_INSTALLED -eq 0 ]; then
+ # Si python3-full está instalado, actualízalo
python3_update
+ elif [ $PYTHON_BASIC_INSTALLED -eq 0 ]; then
+ # Si solo python3 básico está instalado, instala la versión completa
+ echo -e "\n${head_info}: Actualizando a la versión completa de Python..."
+ if [ -f /etc/debian_version ] || [ -f /etc/os-release ]; then
+ apt update
+ apt install -y python3-full
+ else
+ python3_update
+ fi
else
echo -e "\n${head_error}: Python3 no está instalado. Ejecute bin/bootstrap.sh primero."
fi
@@ -172,30 +187,56 @@ update_python_and_pip() {
echo -e "\n${head_error}: pip3 no está instalado. Ejecute bin/bootstrap.sh primero."
echo -e "Esta dependencia es necesaria para varias herramientas del sistema."
fi
+
+ # Update pipx separately
+ command_installed pipx
+ if [ $? -eq 0 ]; then
+ # Función interna para actualizar pipx
+ function pipx_update_internal() {
+ echo "Actualizando pipx..."
+
+ if [ "$(uname)" == "Darwin" ]; then
+ # En macOS, actualizamos pipx a través de Homebrew
+ brew upgrade pipx
+ else
+ # En otros sistemas, actualizamos pipx a través de pip
+ python3 -m pip install --user --upgrade pipx
+ fi
+
+ echo "pipx actualizado correctamente."
+ }
+
+ pipx_update_internal
+ else
+ echo -e "\n${head_error}: pipx no está instalado. Ejecute bin/bootstrap.sh primero."
+ fi
- echo -e "\n${head_info}: Actualización de Python y pip completada."
+ echo -e "\n${head_info}: Actualización de Python, pip y pipx completada."
}
-# Verificar si Python o pip están instalados y si se necesitan actualizar
+# Verificar si Python, pip o pipx están instalados y si se necesitan actualizar
command_installed python3
PYTHON_INSTALLED=$?
command_installed pip3
PIP_INSTALLED=$?
+command_installed pipx
+PIPX_INSTALLED=$?
+
# Si cualquiera de ellos está instalado, necesitamos actualizar con privilegios de superusuario
-if [ $PYTHON_INSTALLED -eq 0 ] || [ $PIP_INSTALLED -eq 0 ]; then
- # Ejecutar la actualización de Python y pip con sudo
- echo -e "\n${head_info}: Se necesitan privilegios de administrador para actualizar Python y pip..."
+if [ $PYTHON_INSTALLED -eq 0 ] || [ $PIP_INSTALLED -eq 0 ] || [ $PIPX_INSTALLED -eq 0 ]; then
+ # Ejecutar la actualización de Python, pip y pipx con sudo
+ echo -e "\n${head_info}: Se necesitan privilegios de administrador para actualizar Python, pip y pipx..."
# Exportar todas las funciones necesarias para que estén disponibles en el subproceso sudo
# Esto incluye command_installed y otras funciones de base.lib que se necesitan
sudo bash -c "$(declare -f command_installed; declare -f update_python_and_pip); update_python_and_pip $SCRIPT_DIR $BIN_LIBS $BIN_MESG $BIN_LANG"
if [ $? -ne 0 ]; then
- echo -e "\n${head_error}: No se pudo actualizar Python y pip. Verifique sus privilegios."
+ echo -e "\n${head_error}: No se pudo actualizar Python, pip y pipx. Verifique sus privilegios."
fi
else
- echo -e "\n${head_info}: No se detectaron Python ni pip instalados. No hay actualizaciones que realizar."
+ echo -e "\n${head_info}: No se detectaron Python, pip ni pipx instalados. No hay actualizaciones que realizar."
echo -e "Para instalar estas dependencias, ejecute bin/bootstrap.sh primero."
fi