hermes-hub/agents/inbox/2026-08-25-A27-in-app-updates.md
Hermes Team 7b7b527103 docs(agents): задание A27 — обновление из самой программы
Владелец обновляется вручную на трёх машинах. Механизм обновления в проекте
есть, но мёртв в каждом звене, и это проверено: веб-клиент check_updates не
вызывает вовсе (0 вхождений); DEFAULT_UPDATE_URL смотрит на заброшенный
второй репозиторий, чей манифест застыл на 0.1.1 от 21 августа; версия
захардкожена в 0.1.1 и подниматься не должна, поэтому сравнение по semver
никогда не скажет «есть обновление».

Рабочая часть — apply_update_sync с резервной копией, py_compile-проверкой и
откатом — сохраняется, переписывать её не нужно.

В задании принято решение, которое агентам не следует угадывать: признак
новизны — коммит, а не версия, источник — релизы основного репозитория, куда
поставка идёт на самом деле.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 17:39:26 +07:00

14 KiB
Raw Blame History

Задание A27: обновление из самой программы

Дата поступления

2026-08-25

База

Проверочный HEAD на момент выдачи: a1e1db7.

Ветка

antigravity/in-app-updates

Порядок исполнения

Два прохода: Flash реализует, Pro проводит аудит. Пункт P0-5 написан для аудитора.


Порядок работы с git

cd <каталог репозитория>; git fetch origin --prune; git status
git checkout main; git pull --ff-only origin main
git checkout -b antigravity/in-app-updates
git commit -m "..."          <- сначала коммит
git push -u origin antigravity/in-app-updates

В main напрямую не пушить. В конце — push и проверка git log --oneline -1, git status чистый.


Задача

Владелец: «а у нас реализовано обновление с программы? чтобы когда выходит новый ревью, в программе появлялось обновить? если нет, надо сделать».

Сейчас обновление ставится вручную: скачать установщик с релиза и запустить. На двух машинах и сервере это делается по несколько раз в день.


Состояние на сегодня — проверено исполнением, заново не выясняйте

Механизм существует, но не работает ни в одном звене. Четыре причины, каждая подтверждена:

1. Веб-интерфейс его не вызывает вообще.

grep -c "check_updates" router/web/static/app.js     -> 0
grep -c "check_updates" router/web/static/index.html -> 0

Кнопка была только в десктопе, который выводится из обращения.

2. Источник обновлений — заброшенный второй репозиторий.

DEFAULT_UPDATE_URL (updater/update_manager.py:77) указывает на ochenstarik-ui/hermes-hub-releases. Репозиторий существует, манифест отдаёт 200, но его содержимое:

version:      0.1.1
published_at: 2026-08-21T09:56:00Z
package_url:  .../releases/download/v0.1.1/hermes-hub-0.1.1.zip

Это состояние до всей работы последних дней. Настоящая поставка давно идёт через релизы основного репозитория ochenstarik-ui/hermes-hub (тег build-2026.08.25), о которых обновлятор не знает.

3. Версия не меняется и меняться не должна.

version.py:4__version__ = "0.1.1", и в заданиях прямо запрещено создавать тег v0.1.1. Сборки в проекте различаются коммитом, а не semver: именно поэтому в deployment_manifest.json пишется git_commit. Сравнение версий в текущем виде никогда не скажет «есть обновление», даже если манифест обновить.

4. Механизм применения при этом рабочий и его не надо переписывать.

UpdateManager.apply_update_sync делает резервную копию src/assets/config/launcher, распаковывает пакет, проверяет каждый .py через py_compile, прогоняет дымовой импорт и откатывается при любой ошибке. Это ценная часть, сохраните её.

paths.get_repo_root() в установленной раскладке возвращает ~/.hermes/plugins/antigravity-provider (там есть assets), то есть цель применения верная.


Решение, которое принято за вас

Чтобы не гадать: признак новизны — коммит, а не версия.

Источник — релизы основного репозитория ochenstarik-ui/hermes-hub. Второй репозиторий hermes-hub-releases из обращения выводится; трогать его не нужно, просто перестаньте на него смотреть.

Установленный коммит уже записан в deployment_manifest.json (git_commit), сборщики его туда кладут — и виндовый, и линуксовый через BUILD_COMMIT. Опубликованный коммит указан в заголовке и в описании релиза.

Если для сравнения удобнее отдельное поле — заведите его в описании релиза или в манифесте, но выводите из реального коммита сборки, а не подставляйте руками.

P0-1. Определение «есть обновление»

Переписать check_for_updates на новый источник.

  1. Опрашивается GitHub API релизов основного репозитория. Репозиторий публичный, токен не нужен; на анонимные запросы есть ограничение по частоте — учтите и не опрашивайте чаще, чем нужно.
  2. Сравнивается установленный коммит с коммитом последнего релиза.
  3. Совпали — «установлена последняя сборка». Разошлись — «доступно обновление» с датой релиза и описанием.
  4. Сеть недоступна — так и сказать. Не «обновлений нет»: это разные утверждения, и путать их нельзя. Прежний код при 404 возвращал update_available=False, то есть отказ выглядел как «всё актуально».

Список разрешённых хостов (ALLOWED_UPDATE_HOSTS) сохраните и дополните, а не убирайте: качать код с произвольного адреса нельзя.

P0-2. Кнопка в веб-интерфейсе

Сейчас её нет. Требуется:

  1. Тихая проверка при запуске и далее по расписанию. Интервал — настройка, не константа.
  2. Когда обновление есть — заметная, но не навязчивая отметка в шапке рядом с версией. Не модальное окно поверх работы.
  3. По нажатию — что за сборка, когда опубликована, что изменилось, и кнопка установки.
  4. Пока обновления нет — показывать установленную сборку и время последней проверки. Это и есть ответ на вопрос «а у меня свежее?».

Действие check_updates уже есть в action_handler (action_handler.py:582), второй реализации не заводить. Появятся новые — впишите в docs/web-api/CONTRACT.md.

P0-3. Установка обновления на обеих платформах

Владелец работает на Windows и на Linux-сервере, где интерфейс открыт по сети. Обе поддерживаются.

Простой и честный путь: скачать тот самый установщик из релиза, который владелец сейчас качает руками, проверить контрольную сумму и запустить. Не изобретайте второй способ доставки — он немедленно разойдётся с первым.

Обязательно:

  • Проверка контрольной суммы до запуска. Суммы публикуются в checksums.txt рядом с установщиками.
  • Сервер перезапускается сам после установки, иначе владелец останется со старым процессом и решит, что обновление не сработало. На Linux запуск идёт через ~/.local/bin/hermes-hub-web.
  • Откат при неудаче. Механизм в apply_update_sync уже есть — используйте его, а не пишите заново.
  • Учётные данные и настройки не трогать. agy_profiles/, hub_settings.json, router_profiles.yaml обязаны пережить обновление. Установщик это умеет («Preserving existing user router_profiles.yaml»), но проверьте отдельно и напишите в отчёте.

Если установку на какой-то платформе решите не автоматизировать — так и напишите, и покажите в интерфейсе готовую команду вместо кнопки. Молчаливо неработающая кнопка хуже честной команды.

P0-4. Ограничение частоты и поведение при отказе

  • Анонимный GitHub API ограничен по частоте. Упёрлись в предел — сообщить об этом прямо, а не выдавать за «обновлений нет».
  • Проверка идёт в фоне и не блокирует интерфейс. Урок оплачен: agy models отвечал десятки секунд и подвешивал окно.
  • Отказ проверки не должен мешать работе хаба.

P0-5. Аудит вторым проходом

  1. Отсутствие данных не выдавать за результат. Главный риск задания: «сеть недоступна» показать как «у вас последняя версия». Ровно эту ошибку делал прежний код при 404.
  2. Проверить на настоящем релизе. Не на заглушке: реальный запрос к API, реальное сравнение коммитов, оба исхода — «есть обновление» и «уже последняя».
  3. Проверить сохранность данных после установки: аккаунты, настройки, цепочки ролей.
  4. Проверить откат: подсунуть заведомо битый пакет и убедиться, что установка откатилась и хаб работает.
  5. Побочные изменения объяснить.
  6. Пропущенный пункт назвать пропущенным.

Ограничения

  • Десктоп (router/ui/**) не трогать.
  • apply_update_sync и список разрешённых хостов не выбрасывать.
  • Второй канал доставки не заводить: источник — релизы основного репозитория.
  • Версию 0.1.1 не поднимать и тег v0.1.1 не создавать.
  • Правило честности без исключений.

Критерии приёмки

  1. Ветка в origin, git status чист.
  2. check_for_updates смотрит на релизы основного репозитория и сравнивает коммиты; проверено настоящим запросом, вывод в отчёте.
  3. Оба исхода показаны: «доступно обновление» и «установлена последняя сборка».
  4. Недоступная сеть и упёртый предел частоты показываются как отказ проверки, а не как отсутствие обновлений; проверено.
  5. В вебе видна установленная сборка и время последней проверки; при наличии обновления — отметка и описание.
  6. Установка работает на Windows и на Linux или честно объявлена неавтоматизированной с показом команды.
  7. Контрольная сумма проверяется до запуска установщика.
  8. После обновления сервер поднят, аккаунты, настройки и цепочки ролей на месте; проверено.
  9. Битый пакет вызывает откат, хаб остаётся работоспособным; проверено.
  10. Проверка не блокирует интерфейс.
  11. ruff check . чисто; релизный гейт не ухудшен.
  12. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed. На main сейчас 442 passed, 2 skipped.

Главное

Владелец обновляется вручную на трёх машинах по несколько раз в день. Нужно, чтобы программа сама сказала «вышла новая сборка» и поставила её, не потеряв аккаунты и не оставив владельца со старым процессом.

Порядок сдачи

Передать точный FINAL_COMMIT_SHA. Сдано только после появления коммита в origin.