#!/bin/sh # ════════════════════════════════════════════════════════════════════════════ # Обновление dsh внутри работающего контейнера — «как плагины», без пересборки. # # Механизм: management console платформы, канал experimental — ставит npm-версию # @deepseek-ai/dsh в /data/platform ( персистентный volume), с пробацией и # автоматическим откатом при неудаче. Код dsh переживает пересоздание контейнера. # # Использование: # scripts/update-dsh.sh # до npm dist-tag latest # scripts/update-dsh.sh check # только показать текущую/доступную версии # scripts/update-dsh.sh --container X # другое имя контейнера (по умолчанию dsh) # # Примечания: # - experimental ставит ТОЛЬКО npm dist-tag latest (вверх). Конкретная версия — # scripts/build-image.sh <версия> + смена DSH_IMAGE в .env. # - Плагины профиля web (/data/dsh) не трогаются и переживают обновление. # ════════════════════════════════════════════════════════════════════════════ set -eu CONTAINER=dsh ACTION=update while [ $# -gt 0 ]; do case "$1" in --container) CONTAINER="$2"; shift 2 ;; check) ACTION=check; shift ;; *) echo "unknown arg: $1" >&2; exit 64 ;; esac done say() { printf '\n=== %s\n' "$*"; } docker inspect -f '{{.State.Running}}' "$CONTAINER" >/dev/null 2>&1 || { echo "Контейнер '$CONTAINER' не запущен. Сначала: docker compose -p dsh up -d" >&2; exit 1; } say "Текущая версия" CURRENT=$(docker exec "$CONTAINER" dsh --version) echo "installed: $CURRENT" say "Доступно на npm" TARGET=$(docker exec "$CONTAINER" node -e "fetch('https://registry.npmjs.org/-/package/@deepseek-ai%2Fdsh/dist-tags').then(r=>r.json()).then(d=>console.log(d.latest)).catch(e=>{console.error(e.message);process.exit(1)})") echo "npm latest: $TARGET" [ "$ACTION" = check ] && exit 0 if [ "$CURRENT" = "$TARGET" ]; then echo "Уже актуально ($CURRENT). Выход."; exit 0 fi say "Переключаю канал на experimental" docker exec "$CONTAINER" dsh-platform channel experimental say "Запускаю обновление (скачивание+установка+рестарт рантайма; это минуты)" if ! docker exec "$CONTAINER" dsh-platform update --wait; then echo "ОШИБКА: обновление не прошло. Диагностика:" >&2 docker exec "$CONTAINER" dsh-platform status || true docker exec "$CONTAINER" dsh-platform logs --source updater --limit 50 || true echo "Платформа обычно сама откатилась к $CURRENT. Повтор: scripts/update-dsh.sh" >&2 exit 1 fi PROBATION=$(docker exec "$CONTAINER" printenv DSH_EXPERIMENTAL_PROBATION_SECONDS || echo 120) say "Пробация ${PROBATION}s — жду автоподтверждение" WAIT=$((PROBATION + 180)); I=0 while [ "$I" -lt "$WAIT" ]; do NEW=$(docker exec "$CONTAINER" dsh --version 2>/dev/null || echo '?') if [ "$NEW" = "$TARGET" ]; then say "Готово: dsh $NEW (было $CURRENT)" docker exec "$CONTAINER" dsh-platform status || true exit 0 fi sleep 15; I=$((I + 15)) done echo "Таймаут ожидания. Текущая версия: $(docker exec "$CONTAINER" dsh --version 2>/dev/null || echo '?')." >&2 echo "Проверьте вручную: docker exec $CONTAINER dsh-platform status" >&2 exit 1