208 lines
No EOL
11 KiB
Bash
208 lines
No EOL
11 KiB
Bash
#!/usr/bin/env bash
|
|
# ============================================================================
|
|
# Simbiot Harness — установка одной командой
|
|
# ============================================================================
|
|
# curl -fsSL https://raw.cil.by/simbiot/install.sh | bash
|
|
# # или из клона репо:
|
|
# bash scripts/install.sh
|
|
#
|
|
# Что делает:
|
|
# 1. Клонирует (или обновляет) репо в ~/simbiot-harness
|
|
# 2. Создаёт Python 3.11+ venv, ставит зависимости (requirements.txt)
|
|
# 3. Кладёт обёртку `simbiot` в ~/.local/bin (аналог hermes: чистый env,
|
|
# exec venv/bin/python cli.py — вне репо работает отовсюду)
|
|
# 4. Флаги: --dir DIR (куда ставить, по умолчанию ~/simbiot-harness),
|
|
# --repo URL (по умолчанию https://git.cil.by/symbiot/simbiot-harness.git),
|
|
# --wizard (визард первого запуска даже в интерактиве не нужен),
|
|
# --no-wizard (тихий режим: без вопросов), -q (минимум вывода).
|
|
# Опционально ставит systemd-юниты (если root и systemd), иначе — как
|
|
# запустить руками, печатает подсказку симулятивно.
|
|
# ============================================================================
|
|
set -euo pipefail
|
|
|
|
REPO_URL="https://git.cil.by/symbiot/simbiot-harness.git"
|
|
INSTALL_DIR="$(eval echo '~')/simbiot-harness"
|
|
WIZARD_AUTO="" # "", "yes", "no"
|
|
QUIET=0
|
|
FORCE_SYSTEMD=""
|
|
INTERACTIVE=0
|
|
[ -t 0 ] && [ -t 1 ] && INTERACTIVE=1
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--dir) INSTALL_DIR="$2"; shift 2 ;;
|
|
--repo) REPO_URL="$2"; shift 2 ;;
|
|
--wizard) WIZARD_AUTO="yes"; shift ;;
|
|
--no-wizard) WIZARD_AUTO="no"; shift ;;
|
|
--systemd) FORCE_SYSTEMD="yes"; shift ;;
|
|
-q|--quiet) QUIET=1; shift ;;
|
|
-h|--help) grep '^#' "$0" | sed -n '2,20p' | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) echo "Неизвестный аргумент: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[0;33m'; NC='\033[0m'
|
|
say() { [ "$QUIET" = 1 ] || echo -e "$1"; }
|
|
|
|
say "${CYAN}⬢ Simbiot Harness — установка${NC}"
|
|
say ""
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 1. Репозиторий
|
|
# ----------------------------------------------------------------------------
|
|
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
say "${CYAN}→${NC} Обновляю существующий клон: $INSTALL_DIR"
|
|
git -C "$INSTALL_DIR" fetch --depth=1 origin >/dev/null 2>&1 || true
|
|
git -C "$INSTALL_DIR" reset --hard origin/HEAD >/dev/null 2>&1 || \
|
|
git -C "$INSTALL_DIR" reset --hard origin/main >/dev/null 2>&1 || true
|
|
# старый PoC-клон мог тащить мусорные/полу-удалённые файлы → чистим трекинг,
|
|
# но сохраняем локальное: venv, .env, *.db, токены
|
|
git -C "$INSTALL_DIR" clean -qfd -e venv -e .env -e '*.db' -e '.simbiot-portal-token' 2>/dev/null || true
|
|
else
|
|
say "${CYAN}→${NC} Клонирую репозиторий → $INSTALL_DIR"
|
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
for i in 1 2 3; do
|
|
git clone --depth=1 "$REPO_URL" "$INSTALL_DIR" && break
|
|
[ "$i" = 3 ] && { echo "Ошибка: клонирование не удалось ($REPO_URL)" >&2; exit 1; }
|
|
sleep 2
|
|
done
|
|
fi
|
|
cd "$INSTALL_DIR"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 2. Python venv + зависимости
|
|
# ----------------------------------------------------------------------------
|
|
if ! command -v python3 >/dev/null 2>&1; then
|
|
echo "python3 не найден. Установи Python 3.11+: apt install -y python3 python3-venv python3-pip" >&2
|
|
exit 1
|
|
fi
|
|
|
|
PYV=$(python3 -c 'import sys; print("%d.%d" % sys.version_info[:2])')
|
|
PYMAJOR=${PYV%%.*}; PYMINOR=${PYV#*.}
|
|
if [ "$PYMAJOR" -lt 3 ] || { [ "$PYMAJOR" = 3 ] && [ "$PYMINOR" -lt 11 ]; }; then
|
|
echo "Нужен Python ≥ 3.11, найден $PYV" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# venv считается годным только если есть И python, И pip (WSL/долгоживущие
|
|
# машины оставляют битые venv: python есть, pip нет → "./venv/bin/pip: No such
|
|
# file or directory"). Битый/неполный пересоздаём.
|
|
if [ ! -x venv/bin/python ] || [ ! -x venv/bin/pip ]; then
|
|
say "${CYAN}→${NC} Создаю venv (python $PYV)…"
|
|
rm -rf venv # сносим битый/неполный venv целиком
|
|
python3 -m venv venv 2>/dev/null || python3 -m venv --without-pip venv
|
|
fi
|
|
say "${CYAN}→${NC} Ставлю зависимости…"
|
|
if [ -x venv/bin/pip ]; then
|
|
./venv/bin/pip install --upgrade pip >/dev/null
|
|
./venv/bin/pip install -r requirements.txt >/dev/null 2>&1 || \
|
|
./venv/bin/pip install -r requirements.txt
|
|
else
|
|
# WSL/deadsnakes-кейс: ensurepip недоступен → ставим зависимости системным pip
|
|
# прямо в site-packages этого venv (python venv подхватит их по sys.path).
|
|
if ! command -v pip3 >/dev/null 2>&1; then
|
|
echo "pip3 не найден. Установи: apt install -y python3-venv python3-pip" >&2
|
|
exit 1
|
|
fi
|
|
say "${YELLOW}→${NC} venv без pip (ensurepip отсутствует) — ставлю зависимости системным pip3 в venv"
|
|
pip3 install --quiet --target="venv/lib/python$PYV/site-packages" -r requirements.txt
|
|
fi
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 3. Обёртка `simbiot` (аналог /usr/local/bin/hermes)
|
|
# ----------------------------------------------------------------------------
|
|
BIN_DIR="$(bash -c 'echo -n "${XDG_BIN_HOME:-$HOME/.local/bin}"')"
|
|
mkdir -p "$BIN_DIR"
|
|
cat > "$BIN_DIR/simbiot" <<EOF
|
|
#!/usr/bin/env bash
|
|
# Simbiot Harness CLI (установлен scripts/install.sh в $INSTALL_DIR)
|
|
unset PYTHONPATH
|
|
unset PYTHONHOME
|
|
cd "$INSTALL_DIR"
|
|
exec ./venv/bin/python cli.py "\$@"
|
|
EOF
|
|
chmod +x "$BIN_DIR/simbiot"
|
|
# PATH: если ~/.local/bin не подхватился (WSL/мак/кастомный профиль) — после
|
|
# установки будет «simbiot: команда не найдена» до перелогина. Добавляем и в
|
|
# текущую сессию, и в rc-файл, и говорим как перечитать.
|
|
_PATH_RC=""
|
|
case "${SHELL##*/}" in
|
|
zsh) _PATH_RC="$HOME/.zshrc" ;;
|
|
*) _PATH_RC="$HOME/.bashrc" ;;
|
|
esac
|
|
case ":$PATH:" in
|
|
*":$BIN_DIR:"*) ;;
|
|
*)
|
|
export PATH="$BIN_DIR:$PATH"
|
|
if [ -f "$_PATH_RC" ] && ! grep -qs '.local/bin' "$_PATH_RC"; then
|
|
printf '\n# Simbiot CLI (scripts/install.sh)\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$_PATH_RC"
|
|
say "${YELLOW}→${NC} добавил PATH в ${_PATH_RC} — открой новую вкладку терминала или: source ${_PATH_RC}"
|
|
else
|
|
say "${YELLOW}→${NC} путь $BIN_DIR добавил только в текущую сессию: если «simbiot: команда не найдена» в новой вкладке — source ${_PATH_RC} или перелогинься."
|
|
fi
|
|
;;
|
|
esac
|
|
say "${GREEN}→${NC} Команда simbiot готова: $BIN_DIR/simbiot"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 4. Первый запуск: init стора (тихо) + визард (если просили/интерактив)
|
|
# ----------------------------------------------------------------------------
|
|
if [ ! -f harness.db ]; then
|
|
if [ "$WIZARD_AUTO" = "no" ] || { [ -z "$WIZARD_AUTO" ] && [ "$INTERACTIVE" = 0 ]; }; then
|
|
say "${CYAN}→${NC} Тихий режим: ./venv/bin/python cli.py init"
|
|
./venv/bin/python cli.py init
|
|
say "${YELLOW}→${NC} Настройки (токен TG, ключ 9router): ${BIN_DIR}/simbiot wizard — когда будешь готов."
|
|
else
|
|
./venv/bin/python cli.py wizard || true
|
|
fi
|
|
fi
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 5. systemd (только если root и просили явно)
|
|
# ----------------------------------------------------------------------------
|
|
if [ "${FORCE_SYSTEMD:-}" = "yes" ]; then
|
|
if [ "$(id -u)" = "0" ] && command -v systemctl >/dev/null 2>&1 && systemctl is-system-running >/dev/null 2>&1; then
|
|
cp "$INSTALL_DIR/scripts/simbiot-harness.service" /etc/systemd/system/ 2>/dev/null || sed -e "s|/root/simbiot-harness|$INSTALL_DIR|g" -e "s|root|$USER|g" "$INSTALL_DIR/scripts/simbiot-harness.service" > /etc/systemd/system/simbiot-harness.service
|
|
systemctl daemon-reload
|
|
systemctl enable --now simbiot-harness
|
|
say "${GREEN}→${NC} systemd: simbiot-harness запущен (systemctl status simbiot-harness)"
|
|
else
|
|
say "${YELLOW}→${NC} systemd-юнит пропущен (нужны root и systemd)."
|
|
fi
|
|
fi
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 6. Проверка одной проверяемой командой
|
|
# ----------------------------------------------------------------------------
|
|
say ""
|
|
if simbiot status >/dev/null 2>&1; then
|
|
say "${GREEN}✅ Установка завершена: simbiot status работает.${NC}"
|
|
else
|
|
echo "⚠ simbiot status вернул ошибку — см. вывод выше." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 7. Следующий шаг: подключение API агенту (ключи берутся на портале)
|
|
# ----------------------------------------------------------------------------
|
|
PORTAL_URL="https://cil.by"
|
|
if [ -s .env ] && grep -q '^ROUTER_KEY=..*' .env 2>/dev/null; then
|
|
say "${GREEN}→${NC} Ключ API уже задан в .env — агент готов."
|
|
say "Дальше: simbiot status (проверка), scripts/install.sh --systemd (автозапуск)."
|
|
else
|
|
say "${CYAN}→${NC} Остался один шаг — подключить API агенту:"
|
|
if [ "$INTERACTIVE" = 1 ]; then
|
|
# macOS / десктоп-линукс / WSL: открываем портал в браузере
|
|
if grep -qi microsoft /proc/version 2>/dev/null; then
|
|
{ command -v wslview >/dev/null 2>&1 && wslview "$PORTAL_URL" >/dev/null 2>&1; } || \
|
|
{ command -v explorer.exe >/dev/null 2>&1 && explorer.exe "$PORTAL_URL" >/dev/null 2>&1 || true; }
|
|
else
|
|
command -v xdg-open >/dev/null 2>&1 && { xdg-open "$PORTAL_URL" >/dev/null 2>&1 || true; }
|
|
fi
|
|
command -v open >/dev/null 2>&1 && { open "$PORTAL_URL" >/dev/null 2>&1 || true; }
|
|
say "→ Открыл портал в браузере (если не открылся — ссылка ниже)."
|
|
fi
|
|
say "${GREEN} $PORTAL_URL${NC} ${CYAN}← залогинься и возьми ключ API${NC}"
|
|
say " Затем: $BIN_DIR/simbiot wizard --router-key <КЛЮЧ>"
|
|
say " (или просто $BIN_DIR/simbiot wizard — спросит всё интерактивно)"
|
|
fi |