docs(agents): задание A57 — вход в Antigravity через сам agy

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

Проверено запуском: подкоманд login или auth у agy нет, вход только запуском CLI
без аргументов. Значит вход переносится в терминал с HOME на каталог профиля,
а браузерный путь остаётся запасным для удалённого случая.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hermes Team 2026-09-01 14:10:49 +07:00
parent f188a18136
commit be98fd6751

View file

@ -0,0 +1,169 @@
# Задание A57: вход в Antigravity через сам agy, а не через сочинённый файл
## Дата поступления
2026-09-01
## База
`origin/main` (`f188a18`).
```
git fetch origin --prune
git checkout -b antigravity/a57-agy-native-login origin/main
```
В `main` напрямую не пушить.
## Порядок исполнения
Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-8** написан для аудитора.
Зона: подключение аккаунтов Antigravity. С A56 (сжатие контекста) не пересекается.
---
## Задача
Сейчас хаб проводит вход сам: получает токены по OAuth и **записывает чужой файл учётных данных своим кодом**. Формат этого файла ревьюер восстановил по рабочему профилю владельца и по строкам в бинарнике `agy`. Сегодня это работает. Но `agy` обновляется, и формат может измениться молча: файл останется на месте, вход перестанет засчитываться, а владелец увидит ровно ту необъяснимую картину, которую ловили полдня — «Авторизация успешно завершена» и тут же «Please sign in to view available models».
Правильный ответ — дать войти самому `agy`, с `HOME`, указывающим на каталог профиля. Тогда он пишет свои файлы своим форматом, сам обновляет токен по истечении часа, и гадать не о чем.
---
## Что проверено ревьюером — заново не выяснять
### Неинтерактивного входа у agy нет
`agy --help` (проверено запуском) даёт подкоманды: `agent`, `agents`, `changelog`, `help`, `install`, `mcp`, `mic-serve`, `models`, `plugin`, `plugins`, `update`. Подкоманд `login` или `auth` **нет**. Вход один: запустить CLI без аргументов и пройти его в терминале. Это же говорит текст ошибки самого agy:
```
Error: Please sign in to view available models.
Launch the CLI without arguments to sign in.
```
Искать скрытый флаг входа не надо — его нет.
### Что agy держит в каталоге профиля
Рабочий профиль владельца `ag-orch-fallback` (11 моделей):
```
.gemini/oauth_creds.json 1949 байт формат Gemini CLI
.gemini/antigravity-cli/antigravity-oauth-token 505 байт {"auth_method":"consumer","token":{...}}
.gemini/antigravity-cli/settings.json 107 байт enableTelemetry, trustedWorkspaces
.gemini/antigravity-cli/installation_id 36 байт
.gemini/antigravity-cli/jetski_state.pbtxt
.gemini/antigravity-cli/history.jsonl
.gemini/antigravity-cli/conversation_summaries.db
auth.json файл хаба, не agy
```
Вход agy читает из `antigravity-oauth-token`, а не из `oauth_creds.json`. Это установлено сравнением рабочего профиля с неработающим и подтверждено исполнением: файл создали руками для `ag-4``agy models` тут же выдал 11 моделей.
### Изоляция по HOME уже работает
`get_profile_env_dir`, `build_safe_subprocess_env` и `hidden_process_kwargs` существуют и применяются: `agy models` вызывается с `HOME`/`USERPROFILE`, указывающими на каталог профиля. Заново это писать не надо.
### Заготовка уже есть
`launch_native_agy_login` в `agy_subprocess.py` запускает agy с `CREATE_NEW_CONSOLE`. Её никто не вызывает — числится мёртвым кодом с A54. Это отправная точка, а не мусор.
### Рост номеров профилей починен
Слот выбирался до входа, когда почта ещё неизвестна, и повторный вход тем же аккаунтом занимал очередной свободный номер: один аккаунт владельца расползся на ag-2, ag-3, ag-4. В `9641957` после опознания почты учётные данные возвращаются в слот, который этот аккаунт уже занимает. **Не переделывать.**
### Среда владельца
Сервер: Ubuntu 24.04, рабочий стол на месте (Chrome запускается), владелец сидит за машиной. Вторая машина — Windows 11. Хаб работает на обеих.
---
## P0-1. Вход выполняет сам agy
1. **Запуск `agy` в настоящем терминале** с `HOME` и `USERPROFILE`, указывающими на каталог выбранного профиля. Владелец проходит вход глазами и руками — это единственный доступный способ.
2. **Терминал не подразумевать, а искать.** На Linux проверить наличие эмулятора (`x-terminal-emulator`, `gnome-terminal`, `konsole`, `xfce4-terminal`, `xterm`) и назвать в отказе, что именно искали. Отсутствие терминала — честный отказ с перечнем проверенного, а не молчание.
3. **Файл учётных данных хаб больше не сочиняет.** `write_agy_oauth_creds` и запись `antigravity-oauth-token` остаются только для запасного браузерного пути (P0-4).
4. **Ждать окончания входа по появлению файла**, а не по коду возврата терминала: эмулятор часто отсоединяется сразу. Ждать `antigravity-oauth-token` в каталоге профиля с разумным пределом и внятным сообщением по его истечении.
## P0-2. Слот выбирается до входа и не меняется
1. **Каталог профиля определяется заранее** и передаётся через `HOME`. Вход физически не может уйти в чужой каталог — в этом весь смысл.
2. **Занятый слот не перезаписывать.** Если в каталоге уже лежит рабочий вход другого аккаунта, предупредить и потребовать подтверждения.
3. **Каталоги существующих аккаунтов не трогать.** Их два десятка, повторный вход руками стоит владельцу часов.
## P0-3. Почта берётся из профиля, а не выдумывается
1. **После входа опознать аккаунт**, прочитав то, что записал agy. Если почту установить не удалось — показать `Н/Д` с причиной, а не подставить правдоподобное.
2. **Проверить двойников** уже существующим `AutoAssigner.check_duplicate_identity` и вернуть учётные данные в занятый этим аккаунтом слот, если он есть.
3. **Число и время получения моделей** показывать рядом со списком.
## P0-4. Браузерный путь остаётся запасным
1. **Не удалять существующий OAuth.** С другой машины через браузер это единственный способ, и он работает.
2. **Владелец выбирает способ** в мастере: вход в терминале на этой машине или по ссылке из браузера. Предлагать первым тот, который на текущей машине выполним.
3. **Текст объясняет разницу**: терминал доступен только там, где стоит хаб.
## P0-5. Отказ доходит до владельца
1. **Причина отказа — текстом.** `agy` пишет её в stderr; она обязана попадать в интерфейс вместе с указанием `HOME`, с которым шёл запуск.
2. **Пустых сообщений быть не должно.** Запасной текст «Отказ выполнения действия» означает потерянную причину.
3. **Проверка после входа не блокирует ответ.** Действие возвращается сразу, опрос провайдера идёт в фоне — это сделано в `0ad946e`, не откатывать.
## P0-6. Безопасность
1. **Токены и коды в интерфейс не выводить и в журнал не писать.** В сообщениях допустимы пути и имена файлов, но не содержимое.
2. **Права на каталог и файлы**`0700` и `0600`.
3. **`~/.hermes/agy_profiles/` не чистить** и не трогать чужие профили.
## P0-7. Проверка исполнением
Тестами это не ловится: все прежние дефекты входа прошли через зелёный прогон.
1. **Подключить аккаунт через терминал на сервере** и приложить вывод `agy models` для этого профиля.
2. **Подключить второй аккаунт** и убедиться, что первый не задет: у обоих свои каталоги и свои почты.
3. **Повторить вход тем же аккаунтом** и убедиться, что новый слот не создаётся.
4. **Проверить отказ** при отсутствии терминала: сообщение перечисляет, что искали.
5. **Проверить, что браузерный путь по-прежнему работает** с другой машины.
## P0-8. Аудит вторым проходом
1. **Пройти вход целиком на обеих машинах**, скриншоты приложить.
2. **Убедиться, что хаб не пишет `antigravity-oauth-token`** на пути через CLI: файл создаёт agy.
3. **Проверить, что при отказе входа профиль не остаётся наполовину заполненным** и не числится подключённым.
4. **Различать «нет доступа» и «не найдено»** — не повторять ошибку ложного диагноза.
5. **Побочные изменения** объяснить.
6. **Пропущенный пункт назвать пропущенным.**
---
## Ограничения
- Учётные данные и каталоги существующих аккаунтов не трогать.
- Правки ревьюера из `main` не откатывать: `9641957` (запись токена и слоты), `0ad946e` (проверка в фоне), `f188a18` (устаревший вердикт).
- Фронтенд без npm, без сборки, без фреймворков — по `docs/web-api/CONTRACT.md` §1.
- Адреса, пути и имена терминалов в код не зашивать вслепую: искать и сообщать, что искали.
- Версию `0.1.3` не понижать.
- Правило честности без исключений: неизмеренное — `Н/Д` с причиной; отсутствие прав — не то же самое, что отсутствие файла.
## Критерии приёмки
1. Ветка в `origin`, `git status` чист.
2. Вход через `agy` в терминале работает на Linux и на Windows; вывод `agy models` приложен.
3. Файл `antigravity-oauth-token` на этом пути создаёт agy, а не хаб.
4. Слот задаётся до входа через `HOME`; чужой каталог затронуть невозможно.
5. Повторный вход тем же аккаунтом не создаёт новый слот.
6. Почта берётся из профиля; неустановленная показывается как `Н/Д` с причиной.
7. Браузерный путь сохранён и проверен с другой машины.
8. Отсутствие терминала даёт отказ с перечнем проверенного.
9. Токены не попадают ни в интерфейс, ни в журнал.
10. `ruff check .` чисто; релизный гейт 10/10; тестов не меньше **626**.
11. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`.
## Главное
Хаб сегодня подделывает чужой формат учётных данных. Это работает ровно до следующего обновления `agy`, и отказ будет молчаливым: файл на месте, вход не засчитан, причина неочевидна. Владелец уже потерял на этом день.
`agy` умеет входить сам и делает это правильно по определению. Задание переносит вход туда, где ему место, оставляя браузерный путь для удалённого случая.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`.