opencode-voice-dictation/docs/handoff/adr/0001-pr-29-v1-18-composer-selectors-fallback-order.md
Sergey af5bc63bcc
fix(ui): support OpenCode 1.18.x composer selectors (#29)
## Что сделано
- Обновлён массив COMPOSER_SELECTORS в src/ui.ts: добавлены новые
селекторы [data-component="prompt-input-v2"] и
[data-component="session-prompt-dock"] как primary для OpenCode v1.18.x
- Старые селекторы session-new-composer/session-composer сохранены как
fallback для обратной совместимости
- README обновлён с указанием совместимой версии OpenCode v1.18.x
(русский и английский блоки)
- Добавлен handoff-документ и ADR 0001 с обоснованием порядка
fallback-селекторов

## Почему
В OpenCode v1.18.x селекторы session-composer/session-new-composer
удалены из исходников, из-за чего findComposer() возвращал null и кнопка
🎤 не появлялась в чате. Порядок массива обновлён как primary (v1.18.x) →
fallback (pre-1.18), чтобы сохранить совместимость с OpenCode <1.18 до
oldInterfaceSunset (2026-09-14).

Closes #28

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-25 01:29:00 +03:00

4.9 KiB
Raw Permalink Blame History

ADR 0001: COMPOSER_SELECTORS fallback order for OpenCode v1.18.x

  • Date: 2026-07-24
  • PR: #29
  • Issue: #28

Статус

Accepted.

Контекст

OpenCode web v1.18.x переименовал контейнер композера:

  • session-composersession-new-composersession-prompt-dock (текущий, обёртка региона)
  • добавлен prompt-input-v2 (v2 form-контейнер внутри PromptInputV2Composer)

Старые селекторы session-composer и session-new-composer полностью удалены из исходников OpenCode v1.18.x (0 совпадений по grep в src/, только упоминания в stories/comments).

Userscript opencode-voice-dictation использует findComposer() в src/ui.ts для позиционирования кнопки микрофона. Массив COMPOSER_SELECTORS перебирается сверху вниз, возвращается первый найденный элемент. С устаревшими селекторами findComposer() возвращал null в v1.18.x — кнопка 🎤 не появлялась.

Дополнительные ограничения:

  • oldInterfaceSunset = 2026-09-14 (packages/app/src/context/settings.tsx:62) — legacy UI окончательно уходит, после этой даты fallback на session-composer станет бесполезен.
  • Home-страница нового layout (NewHome) не содержит композера вообще — userscript активен только на /new-session или открытых сессиях.
  • promptReady() lazy-mount: prompt-input появляется асинхронно после загрузки сообщений; MutationObserver в setupUI корректно отслеживает.

Решение

Обновить COMPOSER_SELECTORS в порядке новое → старое (primary → fallback):

const COMPOSER_SELECTORS = [
  '[data-component="prompt-input-v2"]',        // v2 form-контейнер (v1.18.x primary)
  '[data-component="session-prompt-dock"]',     // v1.18.x регион-обёртка
  '[data-component="session-new-composer"]',   // pre-1.18 fallback
  '[data-component="session-composer"]',       // legacy fallback (<1.17)
];

Альтернативы

1. Только новые селекторы (без fallback)

  • Плюс: проще, нет мёртвого кода после oldInterfaceSunset.
  • Минус: ломает пользователей на OpenCode <1.18 (а это основная установленная база до 14.09.2026). Нарушает acceptance criterion "старые версии остаются совместимы".

2. Только session-prompt-dock (без prompt-input-v2)

  • Плюс: один селектор для региона.
  • Минус: prompt-input-v2 появляется раньше в lifecycle (form-контейнер монтируется внутри dock'а до того, как dock готов). Пропуск prompt-input-v2 задерживает появление кнопки. Issue явно требует оба селектора.

3. Обратный порядок (fallback → primary)

  • Минус: на v1.18.x findComposer() сразу вернёт null для session-composer/session-new-composer (они удалены), потом найдёт session-prompt-dock — работает, но семантически неверно и менее читаемо. Плюс на гибридных сборках может совпасть устаревший элемент первым.

Последствия

  • Кнопка 🎤 появляется в OpenCode v1.18.x (через prompt-input-v2 или session-prompt-dock).
  • Обратная совместимость с OpenCode <1.18 сохранена через session-new-composer / session-composer.
  • После oldInterfaceSunset (14.09.2026) два последних селектора станут мёртвым кодом — можно удалить отдельным PR, не критично.
  • Порядок массива = приоритет детекции; findComposer() без изменений.
  • Не затрагивает src/insert.ts (gate [data-component="prompt-input"] остаётся валидным в обеих версиях UI).

Источники

  • sst/opencode main (commit 2b2aacc, web pkg 1.18.4):
    • packages/app/src/pages/session/composer/session-composer-region.tsx:26session-prompt-dock
    • packages/session-ui/src/v2/components/prompt-input/index.tsx:107prompt-input-v2
    • packages/app/src/context/settings.tsx:62oldInterfaceSunset = 2026-09-14
  • Память: technical/opencode-web-ui-composer-selectors-1.18.4.md