# Задание A19: два установщика — Windows и Linux, запуск веб-интерфейса окном приложения

## Дата поступления
2026-08-23

## База
Проверочный HEAD на момент выдачи: **`fb23bff`**.

## Ветка
`antigravity/installers`

## Кому
Отдельная задача, не пересекается по файлам ни с A17, ни с A18. Брать тому, кто освободится первым.

---

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

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

В конце — push и проверка `git log --oneline -1 origin/antigravity/installers`, `git status` чистый.

---

## Чего хочет владелец

Дословно: «сделай задание на 2 установочника. линукс и виндовс. в винде будет так же создаваться ярлык. при запуске будет открываться окно браузерное но без настроек браузера а как наша десктоп программа. а у линукс ссылка на открытие окна в браузере».

**Так можно, и это стандартный приём.** Chromium-браузеры умеют режим приложения: `--app=URL` открывает окно без адресной строки, вкладок и меню — визуально обычное окно программы.

Проверено ревьюером на машине владельца:

```
Edge   : C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe   — есть
Chrome : C:\Program Files\Google\Chrome\Application\chrome.exe          — есть

msedge.exe --app=http://127.0.0.1:5800/ --window-size=1400,900
-> окно приложения открылось, адресной строки нет
```

## Как это должно работать целиком

Один ярлык делает три вещи по порядку:

1. поднимает веб-сервер, если он ещё не запущен;
2. дожидается готовности — опрашивает `GET /api/health`, а не спит фиксированное время;
3. открывает окно приложения на `http://127.0.0.1:<порт>/`.

Закрытие окна **не должно оставлять висящий сервер**. Решите, как: сервер завершается вместе с окном, либо живёт как фоновая служба и ярлык к нему просто подключается. Второе удобнее для сервера владельца, первое — для десктопа. Выберите и обоснуйте в отчёте.

Команда запуска сервера сейчас:

```
python -m antigravity_provider.router.web
```

Порт по умолчанию 5800, слушает `127.0.0.1`. Настройки читаются из `hub_settings.json` (`web_api_host`, `web_api_port`, `web_api_token`).

---

## P0-1. Windows

**Опираться на существующий установщик**, а не писать новый: `installer/HermesHubSetup.cs` — 1043 строки, в нём уже есть обнаружение Hermes, экран переустановки с показом версий, зеркальное развёртывание `MirrorDirectoryRecursive`, флаги `/silent`, `/uninstall`, `/repair`, `/reinstall` и запись `deployment_manifest.json`. Всё это переиспользуется.

Что добавить:

1. **Ярлык, открывающий веб-интерфейс окном приложения.** Существующий ярлык на десктопное приложение сохранить: десктоп остаётся рабочим и удалять его никто не просил. Итого два ярлыка с понятными именами, либо один на веб и один на десктоп в подпапке меню — на ваше усмотрение, но владелец должен понимать, что чем открывается.

2. **Поиск браузера в порядке**: Edge, Chrome, затем любой Chromium из реестра. **Если ни одного нет — не молчать**: показать понятное сообщение и предложить открыть обычный браузер по адресу. Неработающий ярлык хуже отсутствующего.

3. **Иконка окна.** В режиме `--app` окно берёт иконку из профиля браузера. Если удастся задать свою через `--user-data-dir` с отдельным профилем — хорошо, но **это не обязательное требование**: не тратьте на него больше часа и напишите в отчёте, чем кончилось.

4. Флаг тихой установки должен ставить и веб-ярлык тоже.

## P0-2. Linux

Здесь всё пишется с нуля, но проще: ни реестра, ни `pythonw`, ни возни с venv чужого приложения.

1. **Скрипт установки** `installer/install-linux.sh`: проверяет Python и Hermes, ставит зависимости, разворачивает плагин зеркалом (удаляя устаревшие файлы, как это делает Windows-версия), пишет `deployment_manifest.json`.

2. **`.desktop`-файл** в `~/.local/share/applications/` — это и есть «ссылка на открытие окна в браузере», о которой просит владелец. Запускает тот же скрипт: сервер, ожидание готовности, затем браузер.

3. **Порядок поиска браузера на Linux**: `google-chrome`, `chromium`, `chromium-browser`, `microsoft-edge`. Ни одного не нашлось — открывать `xdg-open` обычным браузером и **сказать пользователю, что окно будет с адресной строкой**, а не притворяться, что всё как задумано.

4. **Учесть headless.** У владельца Ubuntu Server с Xubuntu: он может работать и через SSH без экрана. Если `DISPLAY` и `WAYLAND_DISPLAY` пусты — браузер не запускать, а **напечатать адрес и подсказать проброс порта**:

```
ssh -L 5800:127.0.0.1:5800 user@server
```

Это честный путь, и он единственный рабочий для аккаунтов Antigravity и Claude: их авторизация требует redirect на localhost и на сервере без экрана не работает в принципе. Codex, Grok и OpenCode подключаются без проброса.

5. **Удаление** `installer/uninstall-linux.sh`: убирает программу и `.desktop`, но **не трогает** `~/.hermes/config/router_profiles.yaml`, каталоги профилей, `hub_settings.json`, журналы и телеметрию. То же правило, что и в Windows-версии.

## P0-3. Порт путей уже почти сделан

`paths.py` кроссплатформенный: при отсутствии `LOCALAPPDATA` уходит в `~/.hermes`. A15 провёл через него семь из восьми мест. Осталось `hermes_hub_app.py:37` — **это чинит A17, не трогайте**.

В `agy_subprocess.py` два упоминания `LOCALAPPDATA` уместны: строка 41 — комментарий, строка 414 — список переменных окружения для подпроцесса на Windows.

## P0-4. Проверка на настоящем Linux обязательна

Заявления «должно работать» не принимаются. Если под рукой нет машины — **сказать об этом прямо в отчёте**, и проверку сделает владелец на своём сервере. Это нормальный исход, а вот необоснованное «проверено» — нет.

Минимум, что должно быть проверено вживую или явно отмечено как непроверенное:

- установка проходит на чистой Ubuntu;
- `.desktop` появляется в меню и запускает окно;
- при пустом `DISPLAY` печатается подсказка про проброс порта, а не падает;
- удаление сохраняет данные пользователя.

---

## Ограничения

- Ваши файлы: `installer/**`, `launcher/**`, `scripts/install*.ps1`, `scripts/uninstall*.ps1`, новые `installer/*-linux.sh`, `docs/` в части установки. **Не ваши:** `src/**` целиком — там работают A17 и A18.
- Понадобилась правка в `src/` — скажите, будет заказана отдельно.
- Данные пользователя при переустановке и удалении не трогать.
- Тег `v0.1.1` не создавать.

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

1. Ветка в `origin`, `git status` чист.
2. Windows: установщик создаёт ярлык, открывающий веб-интерфейс окном приложения без адресной строки; ярлык десктопа сохранён.
3. Ярлык поднимает сервер, **дожидается `/api/health`** и только потом открывает окно.
4. Закрытие окна не оставляет висящий процесс сервера; выбранное поведение обосновано в отчёте.
5. Браузер не найден — понятное сообщение и запасной путь, а не тишина.
6. Linux: скрипт установки, `.desktop`, скрипт удаления; зеркальное развёртывание удаляет устаревшие файлы.
7. При пустом `DISPLAY` печатается адрес и команда проброса порта.
8. Удаление сохраняет `router_profiles.yaml`, профили, `hub_settings.json`, журналы.
9. Тихая установка ставит веб-ярлык.
10. В отчёте отдельно сказано, что проверено на настоящем Linux, а что нет.
11. Сборка Windows-установщика без предупреждений компилятора; `ruff check .` чисто.
12. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`.

## Главное

Владелец должен запустить один ярлык и увидеть окно программы — без консоли, без адресной строки, без чтения инструкций. На сервере — открыть адрес и получить то же самое. Всё остальное в этом задании обслуживает эти два сценария.

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