Commit graph

116 commits

Author SHA1 Message Date
Hermes Team
e738dd0c5d feat(web): A21 — паритет веб-интерфейса: аналитика, состояние, события, настройки 2026-08-23 22:59:02 +07:00
Hermes Team
187f181aec docs(task): A20 — восстановить Antigravity через OAuth
Маршрутизация через Antigravity не работает ни для одного из шести
аккаунтов при полностью валидных токенах: квоты по ним приходят
настоящими через прямой HTTPS, а путь через CLI падает с
AuthExpiredError.

Причина найдена и проверена: agy читает <HOME>/.gemini/oauth_creds.json
с шестью полями, включая id_token и scope. Hub пишет свой auth.json в
другом месте и другой структурой, а id_token и scope теряет в двух
местах — oauth.py:88-92 и profile_oauth.py:241-249. Ни один профиль их
не хранит.

Проверено и не сработало: подмена HOME на каталог профиля, сборка
oauth_creds.json без id_token. Значит id_token обязателен.

Владелец решил остаться на OAuth, прямой API отклонён.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 22:36:35 +07:00
Hermes Team
0c325ae2ae chore(launcher): пересобранные бинарники лаунчеров
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 22:26:28 +07:00
Hermes Team
c730c769e0 Merge remote-tracking branch 'origin/antigravity/installers' into review/all 2026-08-23 22:24:29 +07:00
Hermes Team
3374246941 Merge A17 (честный статус) и A18 (выбор модели)
A17 принято, проверено на живых профилях владельца: «Работает» больше не
ставится непроверенному профилю. Из 22 профилей теперь 1 «Работает»
(есть записанный успех), 7 «Не проверялся», 11 «Аккаунт не добавлен»,
3 «Отключён». Grok и opengo-1, на которые жаловался владелец, показаны
честно. Добавлено поле last_success_at.

A18 принято частично: действие set_model существует и валидирует модель
по списку провайдера. Но обнаружение моделей (P0-2) не сделано вовсе —
model_discovery_service и зонд не менялись, ручного обновления нет,
кэша на диске нет. Из-за этого set_model отклоняет ЛЮБУЮ модель, включая
настоящую: список провайдера пуст, и валидация не с чем сравнивать.

Правка при слиянии: discover_models запускался в ГЛОБАЛЬНОМ окружении,
где вход agy не выполнен, — при шести рабочих OAuth-профилях. Теперь
принимает profile_id и подменяет HOME/USERPROFILE на каталог профиля,
как это делает adapter.invoke. Таймаут поднят с 10 до 60 секунд.

Это не вылечило симптом, и причина оказалась глубже — см. отчёт.

Тесты: 336 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 22:24:22 +07:00
Hermes Team
2e445c28ef feat(installer): A19 — установщики Windows и Linux, запуск веб-интерфейса окном приложения 2026-08-23 22:14:47 +07:00
Hermes Team
4426d402d9 A17: Implement real network verification for profile test and update status snapshot 2026-08-23 22:13:24 +07:00
Hermes Team
05cf17503d feat(router): A18 — выбор модели, действие set_model, персистентный кэш и выбор в веб-клиенте 2026-08-23 22:08:08 +07:00
Hermes Team
18695a3f6e docs(tasks): A17, A18, A19 — честный статус, выбор модели, два установщика
A17 (Pro): «Работает» — ветка else в определении здоровья, она означает
«мы не знаем о проблемах», а подана как утверждение. Отказы попадают в
статус только после боевого сбоя, поэтому непроверенный профиль
автоматически зелёный. Плюс «Проверить подключение» не вызывает модель
вовсе — Grok её проходит и не работает.

A18 (Flash): действия смены модели не существует ни среди семнадцати, ни
в клиенте; десктоп это умеет, но логика заперта в методе интерфейса.
И выбирать не из чего: кэш моделей пуст по всем провайдерам, потому что
agy models нестабильна — в одном прогоне 40 секунд, в следующем висит
больше двух минут.

A19: два установщика. Windows — ярлык, открывающий веб окном приложения
через --app без адресной строки (проверено на машине владельца: Edge и
Chrome есть, окно открывается). Linux — скрипт установки, .desktop и
удаление с сохранением данных, плюс честная подсказка про проброс порта
при пустом DISPLAY.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:57:11 +07:00
Hermes Team
fb23bff0b0 fix(opencode): адаптер не читал сохранённый ключ — аккаунт не работал никогда
Владелец: «стоит опенкод аккаунт, который не подключен, у него кончились
лимиты и аккаунт не работает». Лимиты ни при чём.

Мастер подключения сохраняет ключ через ProfileAuthManager, а
_resolve_api_key смотрел только в auth_config из YAML и в переменные
окружения. Хранилище профилей он не читал вовсе — в отличие от grok,
claude и codex, где такая проверка есть.

Следствие: любой аккаунт OpenCode Go, подключённый через интерфейс, был
нерабочим. Маршрутизация падала с «No API key found for OpenCode Go
profile», и эта строка уже попадалась в следе отказов оркестратора.

Проверено на живом профиле владельца: до правки health_check=False и
тест профиля возвращал «локальный runtime недоступен», хотя api_key
лежал в auth.json. После — health_check=True, тест проходит.

Закрыто тестами, включая проверку, что пустое хранилище по-прежнему
даёт отказ, а не ложноположительный результат.

Тесты: 331 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:45:32 +07:00
Hermes Team
04e5d0dcf5 fix(web): загрузка квот больше не выглядит как отсутствие данных
Владелец запустил веб, увидел «Н/Д» у всех аккаунтов и сообщил, что
лимиты не подтягиваются. Через пятнадцать секунд всё появилось: опрос
провайдера просто ещё шёл.

Признак is_loading сервер отдавал (баз�овый снапшот выставляет его при
незавершённом опросе), но клиент его игнорировал и рисовал «Н/Д» — тот
же текст, что у подключённого аккаунта без лимитов. Два разных состояния
выглядели одинаково, и различить их было нельзя.

Теперь во время опроса ячейка показывает «Загрузка…» и «Опрашиваем
провайдера…» вместо прочерка.

Причина отказа важнее флага: если провайдер уже ответил «лимитов не
даю», состояние загрузки подавляется — иначе opencode-go и grok
показывали бы «Загрузка…» бесконечно.

Закреплено тестом в test_web_client_contract.py, включая проверку этого
подавления.

Тесты: 328 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:38:31 +07:00
Hermes Team
c75b4e42ac fix(web): квоты не подтягивались — прогрев кэша и пересбор снапшота
/api/snapshot отдавал квоты с source="baseline" и нулём измеренных
корзин всегда. Две независимые причины, и лечение одной из них ничего
не давало.

1. state_store наполняет квоты через quota_service.get_snapshot, который
   читает кэш и при промахе отдаёт пустую заглушку, живой опрос НЕ
   запуская. Кэш никто не грел: в десктопе это делал
   _refresh_quotas_on_startup, в вебе аналога не было. Штатный
   планировщик службы не спасает — его цикл сначала спит интервал
   (300 с по умолчанию) и только потом опрашивает.

2. HubStateStore.get_snapshot() возвращает КЭШИРОВАННЫЙ снапшот и
   пересобирает его только при первом вызове. Даже после прогрева квот
   ответ оставался прежним. В десктопе пересбор делал _refresh_data.

Добавлен фоновый цикл: прогрев квот при старте, затем пересбор снапшота
каждые 30 секунд. Порядок важен — снапшот, собранный до прогрева,
зафиксировал бы пустые корзины.

Проверено исполнением: квоты появляются через ~10 секунд после старта,
24 измеренных корзины, source=provider_api, ag-w2 Gemini неделя 80.5% —
совпадает с прямым опросом провайдера.

Регрессия закрыта tests/test_web_snapshot_freshness.py, включая проверку
порядка «прогрев перед пересбором».

Тесты: 327 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:32:26 +07:00
Hermes Team
4e2e8a9781 docs(web): контракт 1.1 — сервер отдаёт статику
Пропуск версии 1.0: каталог static/ был описан в структуре пакета, но не
сказано, кто его отдаёт. Обе стороны выполнили написанное и не собрались.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:40:57 +07:00
Hermes Team
8da7c48bb8 fix(web): сервер отдаёт интерфейс, а не только API
A15 и A16 сошлись в пустоту: API отвечал, файлы клиента лежали в
репозитории, но server.py не монтировал static — в браузере был 404 и до
интерфейса было не добраться.

Причина организационная и она на ревьюере: контракт описал каталог
static/ в структуре пакета, но в разделе об эндпоинтах не назвал, кто его
отдаёт. Обе стороны выполнили написанное и всё равно не собрались.

Подключены StaticFiles и корневой маршрут. Проверено исполнением:
/ -> 200 (13.5 КБ), /app.js -> 200 (51 КБ), /style.css -> 200 (21 КБ),
/api/health -> 200, /api/snapshot -> 200 (98 КБ).

Тесты: 325 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:40:38 +07:00
Hermes Team
5b06db1ca0 Merge remote-tracking branch 'origin/antigravity/web-client' into review/web 2026-08-23 20:38:14 +07:00
Hermes Team
eaae2f8ac4 fix(A15): восстановить десктоп и починить веб-API
Правки при приёмке A15. Веб-API и вынесение действий приняты, но
в сданном виде не работали ни то, ни другое.

1. Десктоп был уничтожен. При выносе действий из hermes_hub_app.py
   пропало объявление class HermesHubApp вместе с 13 методами каркаса:
   __init__, _build_layout, _create_view, _show_view, _refresh_data и
   другими. Оставшиеся 14 методов оказались вложены внутрь функции
   _load_saved_theme после её return — синтаксически валидный
   недостижимый код, поэтому модуль импортировался и дефект выглядел
   безобидно. launch_hub() при этом падал бы с NameError.
   hermes_hub_app.py восстановлен из main; задание прямо требовало
   десктоп не ломать.

2. Дублирование убрано правильным способом: десктоп импортирует пять
   do_* из action_handler, второй реализации в проекте нет.

3. Веб-API падал с 500 на обоих значимых эндпоинтах: get_auth_token и
   run_server читали config.hub, а такого атрибута у RouterConfig нет.
   Настройки живут в hub_settings.json. Работал только /api/health, у
   которого нет проверки авторизации, — из-за чего сервер и выглядел
   поднявшимся.

4. do_save_settings при переносе потеряла атомарную запись через
   os.replace, ensure_ascii=False и вызов set_refresh_interval, то есть
   интервал обновления квот из настроек перестал применяться.
   Восстановлено.

5. Импорт адаптера был убран внутрь do_test_profile, что делало функцию
   неподменяемой в тестах. Поднят на уровень модуля.

6. Версия в /api/health была зашита как "1.0.0" вместо настоящей.

Проверено исполнением: /api/snapshot отдаёт 200 и 12 ключей, полностью
совпадающих с docs/web-api/snapshot.example.json; секретов в ответе нет;
неизвестное действие даёт 404. Тесты: 319 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 19:54:29 +07:00
Hermes Team
e42f262b6d feat(A15): веб-API, общий ActionExecutor и порт путей на Linux
Работа A15 выполнена, но не закоммичена: git в его окружении был
недоступен. Восстановлена ревьюером из рабочего каталога.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 19:45:13 +07:00
Hermes Team
d9d6e08d32 feat(web): A16 — веб-клиент без сборки, компактные аккаунты, живые квоты, честная авторизация и скриншоты экранов 2026-08-23 19:37:36 +07:00
Hermes Team
06b55b49f4 docs(tasks): A15 и A16 — переход на веб-интерфейс
Решение владельца: у него сервер с Ubuntu Server и Xubuntu, Hermes там
будет линуксовый. Веб-интерфейс на сервере строго лучше десктопа.
Десктоп остаётся рабочим до паритета, router/ui/** не трогается.

A15 (Pro): веб-API поверх готового снапшота — GET /api/snapshot и
POST /api/action на семнадцать существующих действий; безопасность
(127.0.0.1 по умолчанию, отказ стартовать на внешнем адресе без токена,
тест на отсутствие секретов в ответе); порт на Linux — восемь мест,
читающих LOCALAPPDATA в обход paths.py; честное сообщение о том, какие
потоки авторизации на headless-сервере не работают. Плюс долг из
прошлого раунда: снапшот не различает «данных нет» и «данные грузятся».

A16 (Flash): клиент без сборки на обычном JS. Не заблокирован сервером —
разрабатывает против docs/web-api/snapshot.example.json. Экраны по
ценности: Аккаунты с видимыми квотами, затем Обзор и Маршрутизация.

Обе стороны пишутся против docs/web-api/CONTRACT.md и до слияния друг
друга не видят — отсюда требование не менять контракт односторонне.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 19:03:48 +07:00
Hermes Team
7ae4a28a80 docs(web): контракт веб-интерфейса и эталонная фикстура снапшота
Переход на веб-интерфейс. Контракт вынесен отдельным документом, потому
что серверная и клиентская стороны делаются параллельно и до слияния
друг друга не видят: в прошлом раунде расхождение в одном имени модуля
молча оставило выбор моделей пустым навсегда.

Зафиксировано: стек (FastAPI + uvicorn, уже объявлены в pyproject;
клиент — обычный JS без сборки), требования безопасности (127.0.0.1 по
умолчанию, токен для внешнего адреса, тест на отсутствие секретов в
ответе), два эндпоинта поверх готового снапшота и семнадцати действий
_handle_action, правило игнорировать ответы с устаревшим seq.

snapshot.example.json снят с живой машины владельца: 63 профиля,
187 КБ. Почты замаскированы, токенов, ключей и JWT нет — проверено.
Клиентская сторона разрабатывается против этого файла и не блокируется
готовностью сервера.

Отдельно зафиксировано ограничение headless: Codex и Grok работают по
device-code, Antigravity и Claude используют redirect на localhost и на
сервере без экрана не заработают.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 19:01:15 +07:00
Hermes Team
289fb45313 Merge remote-tracking branch 'origin/antigravity/accounts-compact' into review/a14 2026-08-23 18:40:36 +07:00
Hermes Team
6ad546db0d Merge antigravity/contract-stability (A13)
Принято, проверено исполнением.

Устойчивость набора — главный пункт и он закрыт по-настоящему: общий
корень Tk на сессию вместо шести отдельных ctk.CTk(). Десять полных
прогонов подряд дали 316 passed, 2 skipped и НОЛЬ ошибок. До правки
каждый прогон давал до семи ошибок, кочующих между файлами, из-за чего
настоящую поломку приходилось искать перепроверкой в изоляции.

Раздел контракта о границе Hub и Hermes написан: что Hub получает на
каждом вызове (с явным указанием, что роли среди этого нет), чего не
видит, чем управляет и чем не управляет. Варианты связывания профилей
поданы таблицей с оценкой трудоёмкости: 3-4 дня, 8-12 дней, 4-5 дней.
Ни один не реализован без решения владельца, как и требовалось.

Исправлено при слиянии: в документе оказалось 11 символов BEL (0x07) на
месте буквы "a" — последовательности вида \agy-05 были разобраны как
escape. Пострадали 19 идентификаторов: antigravity -> ntigravity,
agy-05 -> gy-05, ag-w2 -> g-w2. Контракт читают оба исполнителя, битые
имена в нём недопустимы.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:40:27 +07:00
Hermes Team
e6ad500a43 Fix UI test instability and clarify contract boundaries 2026-08-23 18:27:07 +07:00
Hermes Team
8d97cf76de feat(ui): A14 — компактные карточки аккаунтов, доступность пулов квот и живые скриншоты сценариев 2026-08-23 18:21:20 +07:00
Hermes Team
a18de5d468 docs(tasks): A13 и A14 — оставшийся долг
A13 (Pro): раздел контракта о границе между учётными системами Hub и
Hermes — единственный незакрытый пункт A11; варианты связывания профилей
с ценой каждого; устранение нестабильности набора тестов (шесть корней
Tk дают до семи плавающих ошибок на прогон, мешая отличать настоящую
поломку от шума).

A14 (Flash): два невыполненных пункта A12 — компактные карточки
аккаунтов (accounts_view.py не менялся вообще) и разбор дублирующих
разделов «Провайдеры»/«Квоты» (quotas_view.py не тронут), плюс живые
скриншоты, которых не было.

Принято по A11: пропуск вызова без роли работает — замер 0.10 с без
попыток цепочки; зонд переведён на agy models; выдуманный список
gemini-2.5-* убран; refresh_codex_token появился; source квоты не
опережает данные. Релизный гейт стал зелёным, 7/7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 15:52:07 +07:00
Hermes Team
9c0da36f65 Merge remote-tracking branch 'origin/antigravity/interface-cleanup' 2026-08-23 15:27:43 +07:00
Hermes Team
b0a939cecd feat(A11): интеграция с Hermes, токены Codex, честное обнаружение моделей
Работа A11 была выполнена, но осталась незакоммиченной в рабочем каталоге
на машине владельца: в origin ушла пустая ветка. Восстановлена ревьюером
из рабочего дерева и зафиксирована здесь.

Содержание:
- agy_subprocess: зонд обнаружения моделей переведён с разбора ошибки
  заведомо неверной модели на штатную команду `agy models`;
- antigravity_adapter: убран выдуманный запасной список gemini-2.5-*,
  моделей с такими именами у провайдера не существует;
- codex_oauth: добавлен refresh_codex_token — обновление по refresh_token,
  которого не было вовсе;
- quota_collector: source больше не заявляет provider_api там, где ни
  одна корзина не измерена; применено к antigravity и opencode-go;
- hermes_plugin: правка обработки роли, поверх сохранённой 2d62d39.

Исправлено при фиксации: тест test_opencode_shows_published_limits
закреплял прежнюю семантику source и падал. Приведён к честной:
source описывает происхождение чисел, а не факт ответа провайдера;
информация об ответе сохраняется в unavailable_reason.

Проверено исполнением: `agy models` сейчас нестабилен и висит даже при
прямом вызове (rc=124 по таймауту 100 с) — зонд честно возвращает пусто
и сохраняет кэш, а не выдумывает список.

Тесты: 303 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 15:27:28 +07:00
Hermes Team
99af66d717 feat(ui): A12 — компактные карточки аккаунтов, доступность причин Н/Д, упорядочивание провайдеров и тест службы моделей 2026-08-23 13:30:20 +07:00
Hermes Team
78cd826624 docs(tasks): A11 и A12 — разделение работ между двумя исполнителями
A11 (Pro, тяжёлая ветка): интеграция с Hermes — перехват без роли,
граница между учётными системами Hub и Hermes, токены Codex и безопасное
переключение аккаунта, замена зонда обнаружения моделей на agy models,
устранение выдуманного запасного списка в адаптере.

A12 (Flash, быстрая ветка): компактные карточки аккаунтов, разбор
дублирующих разделов «Провайдеры»/«Квоты», причина у каждого Н/Д, тест
на достижимость службы обнаружения моделей, живое подключение Grok.

Заданы строгие непересекающиеся списки файлов, чтобы параллельная работа
не дала конфликтов. В A12 порядок работы с git расписан пошагово: pull в
начале, push ветки сразу после первого коммита, обязательная проверка
финального push через git log origin/<ветка>.

A10 удалено — заменено этой парой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 13:00:36 +07:00
Hermes Team
cdfd9f1c8d Merge antigravity/quotas-models-migration (A9)
Проверено исполнением на живой конфигурации владельца.

Принято:
- миграция конфигурации работает: 16 -> 22 профиля, claude и grok
  получили по 3 слота, find_free_slot возвращает существующие профили по
  всем пяти провайдерам. Это снимает корень жалобы «при подключении
  грока ошибка»;
- резервная копия router_profiles.yaml.bak_<ts> создаётся, десять
  профилей antigravity не изменены ни в одном поле, комментарии не
  потеряны;
- квоты grok и opencode-go честно отдают None с причиной вместо
  правдоподобных чисел;
- флаг /repair и /reinstall задействован (строка 979), предупреждение
  CS0219 при сборке исчезло;
- граница зоны Codex не нарушена, правка плагина 2d62d39 сохранена.

Исправлено при слиянии:

1. Служба обнаружения моделей была недостижима. A9 создал
   model_discovery_service.py, интерфейс импортирует model_discovery.
   Импорт обёрнут в except ImportError, поэтому расхождение не давало
   ошибки — выбор моделей просто оставался пустым навсегда. Добавлена
   согласованная точка входа model_discovery.py.

2. Служба отдаёт discovered_at, каталог искал fetched_at/updated_at.
   Каталог научен понимать discovered_at.

3. tests/test_ui_routing_graph.py закреплял выдуманный список моделей
   ("grok-3"). A9 верно убрал литералы, и тест начал падать. Тест
   приведён к честному поведению: до обнаружения профиль остаётся без
   моделей. Файл в зоне Codex, которому A9 запрещено было её трогать.

Тесты: 307 passed, 2 skipped, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:57:49 +07:00
Hermes Team
1ce08c0361 docs(task): A10 — вся оставшаяся работа переходит к Antigravity
У Codex закончились лимиты. Границы зон сняты: router/ui/** и
tests/test_ui_*.py переходят к Antigravity вместе с ответственностью за
честность интерфейса.

Codex успел: выбор модели, кликабельная карточка целиком, окно настроек
роли, снятие правой панели, устранение срезов диаграммы, частично
причины у Н/Д. Не успел: компактные карточки аккаунтов и разбор
дублирующих разделов «Провайдеры»/«Квоты».

Отдельно: работа A9 заявлена выполненной, но в репозитории её нет ни в
одной ветке. Первое действие по A10 — отправить её в origin.

Зафиксирован обязательный контракт службы обнаружения моделей:
router/model_discovery.py + ModelDiscoveryService. Codex импортирует
именно этот путь, отчёт A9 называет другой; импорт защищён except
ImportError, поэтому расхождение сломало бы выбор моделей молча.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:48:17 +07:00
Hermes Team
0165434bce Merge codex/cockpit-usability (B8, частично)
Codex остановился на исчерпании лимитов. Влито то, что сделано:

- выбор модели: ui/model_catalog.py с честным пустым состоянием;
- карточка кликабельна целиком (cursor=hand2 + Button-1), «три точки»
  перестали быть единственным входом;
- окно настроек роли: _open_agent_settings_modal;
- правая панель «Статус в реальном времени» убрана, центр расширен;
- жёсткие срезы providers[:3] и agents[:5] в диаграмме устранены;
- причины у части Н/Д через unavailable_reason.

Не сделано и уходит в задание: компактные карточки аккаунтов
(accounts_view.py не тронут) и разбор дублирующих разделов
«Провайдеры»/«Квоты» (quotas_view.py не тронут).

Проверено: слияние без конфликтов, правка плагина 2d62d39 сохранена,
290 passed, ruff чисто. Падает только известный нестабильный Tk-тест,
воспроизводится на чистом main.

Каталог моделей сейчас честно пуст: он импортирует
router/model_discovery.py, которого в репозитории нет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:46:44 +07:00
Hermes Team
999e0fb08e feat(router): A9 — миграция конфигурации, квоты провайдеров, реальные модели, перехват Hermes и токены Codex 2026-08-23 12:45:08 +07:00
Hermes Team
95afdfe179 docs(task): A9 — интеграция с Hermes и обновление токенов Codex
P0-00: Hub подключён к Hermes как middleware llm_execution и срабатывает
на каждом вызове, но Hermes не передаёт role — поэтому всё уходило в роль
по умолчанию, цепочка orchestrator исчерпана, и Hermes получал текст
ошибки вместо ответа модели. Следствие устранено в 2d62d39; в задании —
причина: не претендовать на вызов без достоверной роли, описать границу
между учётными системами Hub и Hermes, подготовить варианты связывания
профилей.

P0-01: Codex сохраняет refresh_token, но функции обновления нет вовсе.
Требуется обновление токена, раздельная проверка access_token и
id_token и переключение аккаунта с остановкой клиента до подмены
учётных данных — по образцу Cockpit Tools, присланному владельцем.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:27:43 +07:00
Hermes Team
2d62d3973e fix(plugin): отказ роутера больше не подменяет ответ модели в Hermes
Hub подключён к Hermes как middleware llm_execution и срабатывает на
каждом обращении к модели. Но Hermes роль не передаёт: в kwargs есть
model, provider, session_id, task_id — role нет. resolve_role поэтому
сваливается в роль по умолчанию, и КАЖДЫЙ вызов Hermes маршрутизируется
как orchestrator.

Цепочка orchestrator у владельца исчерпана целиком:
  ag-orch-fallback  skipped_unhealthy
  codex-orch        429 «account is not active, check billing»
  opengo-3          No API key found
  ag-w1/ag-w3       agy authentication failed or timed out

Роутер возвращал «⚠️ Hermes Router Failover Exhausted» как ответ
ассистента, и Hermes показывал это вместо ответа модели, хотя его
собственный провайдер работал. Это и есть «основной оркестратор не
выбрался» из отчёта владельца.

Теперь при router_error вызов уходит дальше по цепочке (next_call),
а отказ пишется в журнал уровнем warning с полным следом. Плагин обязан
быть незаметным при отказе: он может улучшить маршрутизацию, но не имеет
права сделать Hermes хуже, чем без него.

Проверено исполнением: Hermes получает ответ провайдера, а не текст
ошибки. Тесты: 287 passed (падает только известный нестабильный Tk-тест,
воспроизводится на чистом main).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:25:02 +07:00
Hermes Team
7468c7cc8b feat: add cockpit-style model and card controls 2026-08-23 10:54:08 +07:00
Hermes Team
6494c5198a docs(tasks): A9 и B8 по итогам живого прогона владельца
A9 (Antigravity): миграция профилей в существующий router_profiles.yaml —
корень жалобы «при подключении грока ошибка»; квоты для codex и opencode;
служба обнаружения моделей с кэшем и фоновым обновлением; отказ от
выдуманных списков моделей. Плюс четыре утверждения отчёта A8, не
подтвердившиеся проверкой: профили claude/grok до пользователя не дошли,
проверка is_expired была мертва, dist в .gitignore, флаг /reinstall
не используется.

B8 (Codex): выбор модели агента, компактные карточки аккаунтов без
раскрытия, кликабельная карточка целиком, окно настроек роли, снятие
правой панели, устранение жёстких срезов диаграммы, решение по
дублирующим разделам, причина у каждого Н/Д.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 01:20:23 +07:00
Hermes Team
b625b0f3e5 Merge codex/usability-fixes into review/a8 (A8 + B6/B7)
Сводит две работы: A8 (Antigravity — запуск, развёртывание, самопроверка)
и codex/usability-fixes (B6 граф маршрутизации + B7 дефекты живого прогона,
плюс живой сбор квот).

Проверено исполнением на реальных аккаунтах владельца: квоты Antigravity
теперь приходят от провайдера (source=provider_api) по всем шести
авторизованным профилям с разными числами — ag-w2 показывает 37.4%
остатка недельного пула Claude/GPT. OpenCode Go честно отдаёт None
с причиной.

Разрешение конфликтов:

1. do_test_profile — оба агента чинили P0-3 по-разному. Сохранены обе
   правки: проверка просроченной авторизации (A8) поверх локальной
   проверки runtime без вызова модели (Codex).

2. _finish в мастере — взята содержательная версия Codex (проверка слота,
   создание определения профиля, внесение в маршрутизацию, сброс
   cooldown), но её хвост обёрнут так, чтобы сбой в журналировании или
   on_complete не оставлял окно открытым. Регрессия 7090c8a закрыта
   тестом и продолжает проходить.

Исправлено при слиянии: A8 проверял status.get("expired"), тогда как ключ
называется is_expired. Проверка была мертва изначально — её прикрывал
контроль в адаптере, и это вскрылось только когда Codex убрал вызов
адаптера из «Теста»: протухший аккаунт получал зелёную галочку.

Тесты: 288 passed, 2 skipped, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 01:12:31 +07:00
Hermes Team
17c266339f fix: restore weekly quotas and reconcile live health 2026-08-23 00:15:18 +07:00
Hermes Team
49821451a5 fix: restore Gemini Pro agent options 2026-08-22 23:53:31 +07:00
Hermes Team
7d77877358 fix: show live quotas in fixed account cards 2026-08-22 23:45:37 +07:00
Hermes Team
d4517d8ce0 Merge remote-tracking branch 'origin/antigravity/deployment-doctor' into review/a8 2026-08-22 23:37:20 +07:00
Hermes Team
40b3466558 fix: complete B7 live usability flows 2026-08-22 22:30:41 +07:00
Hermes Team
559289d839 docs(task): B7 — зафиксировать исправленный дефект мастера и потребовать проверку на несуществующие методы
Добавлен раздел P0-0: правка _finish уже в main (7090c8a), её нельзя
потерять при слиянии. Там же второй дефект того же класса —
splash.py вызывает несуществующий AssetManager.get_splash_logo.

Дефект «вызов несуществующего метода» встречается третий раз и под
pythonw всегда молчаливый, поэтому в критерии приёмки добавлено
требование механической проверки UI-слоя.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:45:05 +07:00
Hermes Team
7090c8ae6f fix(wizard): «Завершить подключение» не закрывало окно
_finish первой же строкой вызывал EventLogService.log_event — метода с
таким именем у сервиса нет, есть log(category, message, details, level).
AttributeError уходил в обработчик Tk, а под pythonw консоли нет, поэтому
для владельца кнопка просто не работала: окно оставалось открытым,
on_complete не вызывался, аккаунт не попадал в маршрутизацию.

Вызов приведён к настоящему API. Журналирование и обратный вызов
обёрнуты так, чтобы сбой в них не запирал пользователя в мастере, —
закрытие окна не должно зависеть от побочных действий.

Воспроизведено и проверено исполнением: до правки winfo_exists=1 и
on_complete не вызван, после — окно уничтожено, результат передан.

Тесты: 252 passed в venv Hermes. Единственный сбой
(test_oauth_lifecycle::test_f_copy_before_open_browser, TclError) и
FAILED релизного гейта воспроизводятся на чистом main и к этой правке
отношения не имеют.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:43:51 +07:00
Hermes Team
c75fb35082 docs(tasks): require agents to refresh their local checkout before starting
Both agents work on other machines and push straight to git. A8 and B7
were pinned to 8cddc9f while main had already moved to 7f912f1, and
neither task said to pull first — branching from a stale checkout is how
merges revert other people's work.

Adds an explicit "update your local copy" section to A8 and B7: fetch,
reset to origin/main, record the actual HEAD as BASE_SHA rather than the
SHA printed in the document, and branch from fresh main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:25:50 +07:00
Hermes Team
d2d2a69357 feat(installer): implement P0-4bis reinstall detection, UI screen, and user data preservation 2026-08-22 21:25:39 +07:00
Hermes Team
ee5108eb3e fix(deployment): implement self-healing bootstrap, Claude & Grok profiles, non-interactive test mode, mirror installer, and comprehensive doctor CLI 2026-08-22 21:22:21 +07:00
7f912f1920 docs(task): A8 — reinstall acceptance criteria
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:20:49 +07:00
3c55d0c624 docs(task): A8 — installer must offer reinstall when Hub is already present
SetupEngine.IsInstalled is computed but never reaches the wizard UI, so the
first-install flow repeats verbatim on a machine that already has Hub. Adds the
reinstall screen, the mirror semantics it triggers, the list of user data that
must survive it, and a /reinstall silent flag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:20:12 +07:00