# Анатомия обновления dsh изнутри контейнера Зачем: у `dsh` CLI нет команды update, а community-образ пересобирает автор по своему пину (это и есть причина «показывает 0.1.5, когда на npm уже 0.2.x»). Контейнер платформы решает это собственным механизмом обновления — им и пользуемся. ## Кто есть кто в контейнере - **stage0** (PID 1, root) — супервизор платформы: trust-граница, bootstrap, management-сервис, gateway; живёт в образе (`/opt/dsh-platform/runtime`). - **dsh runtime** — сам агент; работает под `node` (uid 1000) через `/run/dsh-platform/views/runtime/bin/dsh` (view поверх управляемого деплоя). - `/usr/local/bin/dsh` и `/usr/local/bin/dsh-platform` — **шимы** (не бинарники): root-вызовы дропают привилегии в node и пробрасывают переменные окружения. - **management console** (`/_dsh_platform/console/`) + CLI `dsh-platform` — управление: статус, каналы, update, rollback, логи. ## Где живут данные (и почему обновление персистентно) | Путь контейнера | Что там | Volume | |---|---|---| | `/data/dsh` | DSH_HOME: профили, **плагины**, settings.yaml, сессии | да | | `/data/platform` | **деплой платформы: runtime-слоты, pristine-копии dsh, snapshots, журнал обновлений** | да | | `/home/node` | HOME: `.dsh-editor` (code-server), кэши | да | | `/opt/dsh-platform` | код платформы из образа | нет (образ) | Experimental-обновление активирует новую версию dsh **в `/data/platform`** → переживает пересоздание контейнера. Откат — тоже (предыдущий runtime-слот). ## Два канала обновления - **stable** — подписанные манифесты автора образа (release-channel на GitHub). Качает bootstrap+environment+dsh. Работает только когда автор выпустил релиз (для 0.2.x его ещё нет — и потому stable-канал нам не подходит). - **experimental** — качает **напрямую с npm** (`OfficialDshDownloader`: canonical `https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-.tgz`, запрет редиректов, контроль sha256/размера, лимиты), поверх текущего bootstrap/environment. Пин `latestSupportedDsh` здесь не блокирует: он автовыдвигается (`advanceSupportedDsh`), а gate для experimental — только «версия больше текущей» (`NpmRegistryClient.latest`). ## Командный путь обновления (что делает `scripts/update-dsh.sh`) 1. `dsh-platform channel experimental` — переключить канал (PUT `/channel`). 2. `dsh-platform update --wait` — coordinator: скачать tarball с npm → «candidate deployment» → пауза dsh-runtime → активация → resume. 3. Пробация `DSH_EXPERIMENTAL_PROBATION_SECONDS` (по умолчанию 120 c): платформа мониторит здоровье dsh; провал → **автооткат** к предыдущему деплою; успех → candidate коммитится (`deployments/candidate/commit`). 4. Проверка: `dsh --version` == npm latest. Автопроверка обновлений платформой: раз в ~6 ч (21600 c), отключается/настраивается в Management Console (Automatic checks). ## Если что-то пошло не так ```sh docker exec dsh dsh-platform status docker exec dsh-platform logs --source updater --limit 100 docker exec dsh dsh-platform rollback # вернуться к предыдущему деплою ``` Coordinator сам восстанавливается после прерванного обновления (journal + snapshots + `recover`). Кнопка «return stable» в консоли откатывает и данные-снапшот (требует интерактивного подтверждения — это осознанная потеря данных новее снапшота). ## Известные ограничения - Experimental ставит **только npm dist-tag `latest`** (политика платформы). Конкретная версия — путь `scripts/build-image.sh ` + новая `DSH_IMAGE`. - Плагины и профили (`/data/dsh`) обновлением dsh не трогаются; при мажорном скачке возможна несовместимость плагинов — лечение: `dsh plugin --profile web update`. - Stage0/bootstrap/environment остаются от образа; обновляется только слой dsh.