v1.8.97: add install.sh — CLI installer for headless Linux servers

Installs ssh.py, encryption.py, Claude Code skill, Python dependencies.
Supports local source dir or downloads from Gitea.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-03-02 06:28:18 -05:00
parent 7af788b72e
commit b7e9c80690
3 changed files with 277 additions and 1 deletions

276
tools/install.sh Normal file
View File

@@ -0,0 +1,276 @@
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────
# ServerManager CLI Installer for Linux (headless / no-GUI)
#
# Устанавливает:
# - ssh.py + encryption.py → ~/.server-connections/
# - servers.json + settings.json → ~/.server-connections/ (если есть)
# - CLAUDE.md → ~/.claude/
# - ssh.md (скилл) → ~/.claude/commands/
# - Python-зависимости для CLI (paramiko, cryptography, etc.)
#
# Запуск:
# curl -sSL https://git.sensey24.ru/aibot777/server-manager/raw/branch/master/tools/install.sh | bash
# или:
# bash install.sh
# или с указанием источника файлов:
# bash install.sh /path/to/server-manager/
# ─────────────────────────────────────────────────────────────────────
set -euo pipefail
# ── Colors ──
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; }
step() { echo -e "\n${CYAN}━━━ $* ━━━${NC}"; }
# ── Config ──
CONN_DIR="$HOME/.server-connections"
CLAUDE_DIR="$HOME/.claude"
COMMANDS_DIR="$CLAUDE_DIR/commands"
GITEA_RAW="https://git.sensey24.ru/aibot777/server-manager/raw/branch/master"
# Source directory (optional argument)
SRC_DIR="${1:-}"
# ── Banner ──
echo -e "${CYAN}"
echo "╔══════════════════════════════════════════════╗"
echo "║ ServerManager CLI Installer for Linux ║"
echo "║ github: git.sensey24.ru/aibot777 ║"
echo "╚══════════════════════════════════════════════╝"
echo -e "${NC}"
# ── Step 1: Check Python ──
step "1/5 Проверка Python"
PYTHON=""
for cmd in python3 python; do
if command -v "$cmd" &>/dev/null; then
ver=$("$cmd" --version 2>&1 | grep -oP '\d+\.\d+')
major=$(echo "$ver" | cut -d. -f1)
minor=$(echo "$ver" | cut -d. -f2)
if [ "$major" -ge 3 ] && [ "$minor" -ge 8 ]; then
PYTHON="$cmd"
ok "Python найден: $($cmd --version)"
break
fi
fi
done
if [ -z "$PYTHON" ]; then
error "Python 3.8+ не найден!"
echo " Установите: sudo apt install python3 python3-pip"
echo " или: sudo yum install python3 python3-pip"
exit 1
fi
# Check pip
PIP=""
for cmd in pip3 pip; do
if command -v "$cmd" &>/dev/null; then
PIP="$cmd"
break
fi
done
if [ -z "$PIP" ]; then
# Try python -m pip
if $PYTHON -m pip --version &>/dev/null; then
PIP="$PYTHON -m pip"
else
error "pip не найден!"
echo " Установите: sudo apt install python3-pip"
exit 1
fi
fi
ok "pip найден: $($PIP --version 2>&1 | head -1)"
# ── Step 2: Install Python dependencies ──
step "2/5 Установка Python-зависимостей"
CLI_DEPS=(
"paramiko>=3.4.0"
"cryptography>=41.0.0"
"pymysql>=1.1.0"
"psycopg2-binary>=2.9.9"
"redis>=5.0.0"
"requests>=2.31.0"
)
for dep in "${CLI_DEPS[@]}"; do
pkg=$(echo "$dep" | sed 's/[>=<].*//')
if $PYTHON -c "import $pkg" 2>/dev/null; then
ok "$pkg уже установлен"
else
info "Устанавливаю $dep..."
if $PIP install "$dep" --quiet 2>/dev/null; then
ok "$dep установлен"
else
warn "Не удалось установить $dep (попробуйте: $PIP install $dep)"
fi
fi
done
# ── Step 3: Create directories ──
step "3/5 Создание директорий"
mkdir -p "$CONN_DIR" "$COMMANDS_DIR"
chmod 700 "$CONN_DIR"
ok "$CONN_DIR"
ok "$COMMANDS_DIR"
# ── Step 4: Copy/Download files ──
step "4/5 Установка файлов"
copy_or_download() {
local src_relative="$1"
local dst="$2"
local perms="$3"
local desc="$4"
# Try local source first
if [ -n "$SRC_DIR" ] && [ -f "$SRC_DIR/$src_relative" ]; then
cp "$SRC_DIR/$src_relative" "$dst"
chmod "$perms" "$dst"
ok "$desc (из $SRC_DIR)"
return 0
fi
# Try download from Gitea
local url="$GITEA_RAW/$src_relative"
if command -v curl &>/dev/null; then
if curl -sSL -o "$dst" "$url" 2>/dev/null; then
# Verify not empty and not HTML error page
if [ -s "$dst" ] && ! head -1 "$dst" | grep -qi '<!doctype\|<html'; then
chmod "$perms" "$dst"
ok "$desc (скачан с Gitea)"
return 0
fi
rm -f "$dst"
fi
elif command -v wget &>/dev/null; then
if wget -q -O "$dst" "$url" 2>/dev/null; then
if [ -s "$dst" ] && ! head -1 "$dst" | grep -qi '<!doctype\|<html'; then
chmod "$perms" "$dst"
ok "$desc (скачан с Gitea)"
return 0
fi
rm -f "$dst"
fi
fi
warn "$desc — не удалось скачать. Скопируйте вручную."
return 1
}
# Core files (always install)
copy_or_download "tools/ssh.py" "$CONN_DIR/ssh.py" "755" "ssh.py"
copy_or_download "core/encryption.py" "$CONN_DIR/encryption.py" "644" "encryption.py"
# Claude Code skill
copy_or_download "tools/skill-ssh.md" "$COMMANDS_DIR/ssh.md" "644" "ssh.md (скилл /ssh)"
# CLAUDE.md
if [ -n "$SRC_DIR" ] && [ -f "$SRC_DIR/CLAUDE.md" ]; then
cp "$SRC_DIR/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md"
chmod 644 "$CLAUDE_DIR/CLAUDE.md"
ok "CLAUDE.md"
fi
# servers.json — only copy if exists locally, never download (contains encrypted creds)
if [ -n "$SRC_DIR" ] && [ -f "$SRC_DIR/servers.json" ]; then
cp "$SRC_DIR/servers.json" "$CONN_DIR/servers.json"
chmod 600 "$CONN_DIR/servers.json"
ok "servers.json (зашифрованный)"
elif [ ! -f "$CONN_DIR/servers.json" ]; then
warn "servers.json не найден — скопируйте с основной машины:"
echo " scp user@main:~/.server-connections/servers.json $CONN_DIR/"
fi
# settings.json
if [ -n "$SRC_DIR" ] && [ -f "$SRC_DIR/settings.json" ]; then
cp "$SRC_DIR/settings.json" "$CONN_DIR/settings.json"
chmod 600 "$CONN_DIR/settings.json"
ok "settings.json"
elif [ ! -f "$CONN_DIR/settings.json" ]; then
# Create minimal settings
echo '{"language":"en","check_interval":60}' > "$CONN_DIR/settings.json"
chmod 600 "$CONN_DIR/settings.json"
ok "settings.json (создан по умолчанию)"
fi
# ── Step 5: Verify ──
step "5/5 Проверка установки"
ALL_OK=true
if [ -f "$CONN_DIR/ssh.py" ] && [ -x "$CONN_DIR/ssh.py" ]; then
ok "ssh.py — исполняемый"
else
error "ssh.py — не найден или не исполняемый"
ALL_OK=false
fi
if [ -f "$CONN_DIR/encryption.py" ]; then
ok "encryption.py"
else
error "encryption.py — не найден"
ALL_OK=false
fi
if [ -f "$COMMANDS_DIR/ssh.md" ]; then
ok "ssh.md скилл"
else
warn "ssh.md скилл — не найден"
fi
if [ -f "$CONN_DIR/servers.json" ]; then
ok "servers.json"
else
warn "servers.json — отсутствует (нужно скопировать вручную)"
fi
# Test ssh.py
info "Тест ssh.py..."
if $PYTHON "$CONN_DIR/ssh.py" --list &>/dev/null; then
ok "ssh.py --list работает"
else
if [ ! -f "$CONN_DIR/servers.json" ]; then
warn "ssh.py не может запуститься (нет servers.json)"
else
warn "ssh.py вернул ошибку — проверьте зависимости"
fi
fi
# ── Summary ──
echo ""
echo -e "${CYAN}━━━ Готово ━━━${NC}"
echo ""
if $ALL_OK; then
echo -e "${GREEN}Установка завершена успешно!${NC}"
else
echo -e "${YELLOW}Установка завершена с предупреждениями.${NC}"
fi
echo ""
echo "Файлы:"
echo " $CONN_DIR/ssh.py — CLI-утилита"
echo " $CONN_DIR/encryption.py — модуль шифрования"
echo " $CONN_DIR/servers.json — серверы (зашифрованные)"
echo " $COMMANDS_DIR/ssh.md — скилл /ssh для Claude Code"
echo ""
echo "Использование:"
echo " python3 ~/.server-connections/ssh.py --list"
echo " python3 ~/.server-connections/ssh.py --info ALIAS"
echo " python3 ~/.server-connections/ssh.py ALIAS \"command\""
echo ""
echo "Claude Code скилл: /ssh"
echo ""