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>
This commit is contained in:
parent
8de6ca3c7e
commit
af5bc63bcc
10 changed files with 360 additions and 3 deletions
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
Голосовая диктовка для [OpenCode](https://opencode.ai) web через Whisper (Groq API). Работает на ПК и телефоне.
|
Голосовая диктовка для [OpenCode](https://opencode.ai) web через Whisper (Groq API). Работает на ПК и телефоне.
|
||||||
|
|
||||||
> ⚠️ **Требуется новый интерфейс OpenCode.** В настройках OpenCode web включите «New UI» — в старом интерфейсе скрипт не работает.
|
> ⚠️ **Требуется OpenCode web v1.18.x.** В настройках OpenCode web включите «New UI» — в старом интерфейсе скрипт не работает. Совместимо с OpenCode v1.18.x; старые версии поддерживаются через fallback-селекторы.
|
||||||
|
|
||||||
### Установка
|
### Установка
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
||||||
Voice dictation for [OpenCode](https://opencode.ai) web via Whisper (Groq API). Works on desktop and mobile.
|
Voice dictation for [OpenCode](https://opencode.ai) web via Whisper (Groq API). Works on desktop and mobile.
|
||||||
|
|
||||||
> ⚠️ **Requires the new OpenCode UI.** In OpenCode web settings, enable "New UI" — the script does not work in the old interface.
|
> ⚠️ **Requires OpenCode web v1.18.x.** In OpenCode web settings, enable "New UI" — the script does not work in the old interface. Compatible with OpenCode v1.18.x; older versions are supported via fallback selectors.
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# 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-composer` → `session-new-composer` → **`session-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):
|
||||||
|
|
||||||
|
```js
|
||||||
|
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:26` — `session-prompt-dock`
|
||||||
|
- `packages/session-ui/src/v2/components/prompt-input/index.tsx:107` — `prompt-input-v2`
|
||||||
|
- `packages/app/src/context/settings.tsx:62` — `oldInterfaceSunset = 2026-09-14`
|
||||||
|
- Память: `technical/opencode-web-ui-composer-selectors-1.18.4.md`
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# 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-composer` → `session-new-composer` → **`session-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):
|
||||||
|
|
||||||
|
```js
|
||||||
|
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:26` — `session-prompt-dock`
|
||||||
|
- `packages/session-ui/src/v2/components/prompt-input/index.tsx:107` — `prompt-input-v2`
|
||||||
|
- `packages/app/src/context/settings.tsx:62` — `oldInterfaceSunset = 2026-09-14`
|
||||||
|
- Память: `technical/opencode-web-ui-composer-selectors-1.18.4.md`
|
||||||
98
docs/handoff/pr-29-v1-18-composer-selectors.md
Normal file
98
docs/handoff/pr-29-v1-18-composer-selectors.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
---
|
||||||
|
pr_number: 29
|
||||||
|
branch: fix/ui/v1-18-composer-selectors
|
||||||
|
issue: 28
|
||||||
|
title: support OpenCode 1.18.x composer selectors
|
||||||
|
status: open
|
||||||
|
created: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# Handoff — PR #29: v1.18.x composer selectors
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Userscript opencode-voice-dictation не вставляет кнопку микрофона в OpenCode web v1.18.x — `findComposer()` в `src/ui.ts` возвращал `null`, потому что массив `COMPOSER_SELECTORS` содержал только устаревшие селекторы `[data-component="session-composer"]` и `[data-component="session-new-composer"]`, которые полностью удалены из исходников OpenCode v1.18.x.
|
||||||
|
|
||||||
|
В OpenCode v1.18.x контейнер композера переименован:
|
||||||
|
- `[data-component="session-prompt-dock"]` — обёртка региона композера (`packages/app/src/pages/session/composer/session-composer-region.tsx:26`)
|
||||||
|
- `[data-component="prompt-input-v2"]` — v2 form-контейнер (`packages/session-ui/src/v2/components/prompt-input/index.tsx:107`)
|
||||||
|
|
||||||
|
Уцелели в v1.18.x (НЕ трогались): `[data-component="prompt-input"]` (contenteditable), `[data-action="prompt-submit"]` (кнопка отправки), `[data-slot="question-custom-input"]` (textarea).
|
||||||
|
|
||||||
|
Issue: #28.
|
||||||
|
|
||||||
|
## Что сделано
|
||||||
|
|
||||||
|
- Обновлён массив `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 для обратной совместимости с OpenCode <1.18.
|
||||||
|
- `README.md` обновлён с указанием совместимой версии OpenCode v1.18.x (русский и английский блоки).
|
||||||
|
- Добавлен 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). Функция `findComposer()` уже перебирает массив сверху вниз — изменений в логике не потребовалось.
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
- После `oldInterfaceSunset` (2026-09-14) legacy-селекторы `session-new-composer` / `session-composer` станут мёртвым кодом — удалить отдельным PR.
|
||||||
|
- Отслеживать дальнейшие переименования контейнера композера в OpenCode (источник: `sst/opencode` main).
|
||||||
|
|
||||||
|
## Watch out
|
||||||
|
|
||||||
|
- Порядок `COMPOSER_SELECTORS` = приоритет детекции; не менять без обновления ADR 0001.
|
||||||
|
- `prompt-input-v2` появляется раньше `session-prompt-dock` в lifecycle (form-контейнер монтируется внутри dock'а) — порядок primary→fallback важен для раннего появления кнопки.
|
||||||
|
- Home-страница нового layout (`NewHome`) не содержит композера — userscript активен только на `/new-session` или открытых сессиях.
|
||||||
|
- `src/insert.ts` не затронут: gate `[data-component="prompt-input"]` остаётся валидным в обеих версиях UI.
|
||||||
|
|
||||||
|
## Изменения
|
||||||
|
|
||||||
|
### `src/ui.ts`
|
||||||
|
- Обновлён массив `COMPOSER_SELECTORS` (новые селекторы v1.18.x первыми как primary, старые сохранены как fallback):
|
||||||
|
```js
|
||||||
|
const COMPOSER_SELECTORS = [
|
||||||
|
'[data-component="prompt-input-v2"]',
|
||||||
|
'[data-component="session-prompt-dock"]',
|
||||||
|
'[data-component="session-new-composer"]',
|
||||||
|
'[data-component="session-composer"]',
|
||||||
|
];
|
||||||
|
```
|
||||||
|
- Функция `findComposer()` уже перебирает массив — изменений не потребовалось.
|
||||||
|
|
||||||
|
### `README.md`
|
||||||
|
- Строка 13 (русский блок): предупреждение о "New UI" уточнено до совместимой версии OpenCode v1.18.x.
|
||||||
|
- Строка 68 (english-блок): аналогичное уточнение для английского блока.
|
||||||
|
|
||||||
|
### Файлы вне спеки
|
||||||
|
- `src/insert.ts`, `src/audio.ts`, `src/transcribe.ts`, `src/config.ts`, `src/keyboard.ts`, `src/types.ts`, `src/index.ts` — без изменений.
|
||||||
|
|
||||||
|
## Проверки
|
||||||
|
|
||||||
|
| Проверка | Команда | Результат |
|
||||||
|
|----------|---------|----------|
|
||||||
|
| Lint | `npm run lint` (biome check) | ✅ Checked 21 files, no fixes |
|
||||||
|
| Typecheck | `npm run typecheck` (tsc --noEmit) | ✅ No errors |
|
||||||
|
| Tests | `npm run test` (vitest run) | ✅ 47/47 passed (5 files) |
|
||||||
|
| Knip | `npm run knip` | ✅ No unused exports |
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
- [x] Кнопка 🎤 появляется в OpenCode web v1.18.x (через новые primary-селекторы `prompt-input-v2` / `session-prompt-dock`)
|
||||||
|
- [x] Старые версии OpenCode остаются совместимы (fallback-селекторы `session-new-composer` / `session-composer` сохранены)
|
||||||
|
- [x] `npm run lint && npm run typecheck && npm run test && npm run knip` проходят
|
||||||
|
- [x] README обновлён с указанием совместимой версии OpenCode v1.18.x (русский и английский блоки)
|
||||||
|
|
||||||
|
## Коммиты
|
||||||
|
|
||||||
|
1. `fix(ui): add v1.18.x composer selectors` — обновление `COMPOSER_SELECTORS` в `src/ui.ts`
|
||||||
|
2. `docs(readme): specify OpenCode v1.18.x compatibility` — уточнение совместимости в обоих языковых блоках README
|
||||||
|
3. `docs(handoff): add handoff + ADR for PR` — handoff-документ и ADR
|
||||||
|
4. `docs(handoff): set PR number` — подстановка реального номера PR (после `gh pr create`)
|
||||||
|
|
||||||
|
## ADR
|
||||||
|
|
||||||
|
См. `docs/handoff/adr/0001-pr-29-v1-18-composer-selectors-fallback-order.md`.
|
||||||
|
|
||||||
|
## Источники
|
||||||
|
|
||||||
|
- Память: `technical/opencode-web-ui-composer-selectors-1.18.4.md` (исследование `sst/opencode` main commit 2b2aacc, web pkg 1.18.4)
|
||||||
|
- Память: `repos/opencode-voice-dictation.md` (архитектура репо)
|
||||||
30
docs/project-map/README.md
Normal file
30
docs/project-map/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
module: .
|
||||||
|
purpose: Index of project structure and top-level modules
|
||||||
|
last_updated: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project Map — opencode-voice-dictation
|
||||||
|
|
||||||
|
Userscript для голосовой диктовки в OpenCode web через Whisper (Groq API). Точки входа в UI OpenCode определяются через массив `COMPOSER_SELECTORS` в `src/ui.ts` (primary для v1.18.x + fallback для pre-1.18).
|
||||||
|
|
||||||
|
## Top-level modules
|
||||||
|
|
||||||
|
- [`src/`](./src.md) — исходники userscript (entry, ui, audio, transcribe, insert, config, keyboard, types)
|
||||||
|
- [`tests/`](./tests.md) — unit-тесты (vitest) + моки
|
||||||
|
- [`.github/`](./github.md) — CI workflows, dependabot, release
|
||||||
|
- [`docs/`](./docs.md) — handoff, ADR, project map
|
||||||
|
|
||||||
|
## Build / tooling
|
||||||
|
|
||||||
|
- `vite.config.ts` + `vite-plugin-monkey` — сборка userscript (.user.js)
|
||||||
|
- `biome.json` — lint/format
|
||||||
|
- `tsconfig.json` — TypeScript
|
||||||
|
- `knip.json` — детектор неиспользуемого кода
|
||||||
|
- `vitest.config.ts` — test runner
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Один handoff на PR: `docs/handoff/pr-<N>-<slug>.md` с секциями `## Что сделано`, `## Почему`, `## Pending`, `## Watch out`.
|
||||||
|
- ADR на архитектурное решение: `docs/handoff/adr/<NNNN>-<slug>.md` с секциями `## Статус`, `## Контекст`, `## Решение`, `## Альтернативы`.
|
||||||
|
- Селекторы OpenCode UI — primary (новые) → fallback (старые), порядок = приоритет детекции.
|
||||||
21
docs/project-map/docs.md
Normal file
21
docs/project-map/docs.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
module: docs
|
||||||
|
purpose: Handoff-документы, ADR, project map
|
||||||
|
key_files:
|
||||||
|
- docs/handoff/pr-<N>-<slug>.md — handoff на PR
|
||||||
|
- docs/handoff/adr/<NNNN>-<slug>.md — архитектурные решения
|
||||||
|
- docs/project-map/ — карта структуры проекта
|
||||||
|
dependencies: []
|
||||||
|
last_updated: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# docs/
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- `handoff/pr-<N>-<slug>.md` — handoff на PR (секции: Что сделано, Почему, Pending, Watch out)
|
||||||
|
- `handoff/adr/<NNNN>-<slug>.md` — архитектурные решения (секции: Статус, Контекст, Решение, Альтернативы)
|
||||||
|
- `project-map/` — карта структуры проекта (README + по файлу на модуль)
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
- Один handoff на PR, slug = тема PR.
|
||||||
|
- ADR нумеруются с 0001.
|
||||||
17
docs/project-map/github.md
Normal file
17
docs/project-map/github.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
module: .github
|
||||||
|
purpose: CI workflows, dependabot, release
|
||||||
|
key_files:
|
||||||
|
- .github/workflows/ci.yml — CI (lint, typecheck, test, knip)
|
||||||
|
- .github/workflows/release.yml — релиз + GitHub Release
|
||||||
|
- .github/dependabot.yml — авто-обновление зависимостей
|
||||||
|
dependencies: []
|
||||||
|
last_updated: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# .github/
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- `workflows/ci.yml` — CI (lint, typecheck, test, knip)
|
||||||
|
- `workflows/release.yml` — релиз + GitHub Release
|
||||||
|
- `dependabot.yml` — авто-обновление зависимостей
|
||||||
31
docs/project-map/src.md
Normal file
31
docs/project-map/src.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
module: src
|
||||||
|
purpose: Исходники userscript — UI, аудио-захват, транскрипция, вставка текста
|
||||||
|
key_files:
|
||||||
|
- src/index.ts — entry point userscript
|
||||||
|
- src/ui.ts — позиционирование кнопки 🎤, COMPOSER_SELECTORS, findComposer()
|
||||||
|
- src/audio.ts — захват микрофона (MediaRecorder)
|
||||||
|
- src/transcribe.ts — отправка в Groq Whisper API
|
||||||
|
- src/insert.ts — вставка транскрипта в prompt-input
|
||||||
|
- src/config.ts — настройки (API key, hotkey, language)
|
||||||
|
- src/keyboard.ts — глобальный hotkey
|
||||||
|
- src/types.ts — shared типы
|
||||||
|
dependencies: []
|
||||||
|
last_updated: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# src/
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- `index.ts` — entry point userscript
|
||||||
|
- `ui.ts` — позиционирование кнопки 🎤, `COMPOSER_SELECTORS`, `findComposer()`, MutationObserver
|
||||||
|
- `audio.ts` — захват микрофона (MediaRecorder)
|
||||||
|
- `transcribe.ts` — отправка в Groq Whisper API
|
||||||
|
- `insert.ts` — вставка транскрипта в prompt-input (gate `[data-component="prompt-input"]`)
|
||||||
|
- `config.ts` — настройки (API key, hotkey, language)
|
||||||
|
- `keyboard.ts` — глобальный hotkey
|
||||||
|
- `types.ts` — shared типы
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
- Селекторы OpenCode UI собраны в массив `COMPOSER_SELECTORS` (primary → fallback), `findComposer()` перебирает сверху вниз.
|
||||||
|
- UI-элементы появляются асинхронно — отслеживаются через MutationObserver в `setupUI`.
|
||||||
26
docs/project-map/tests.md
Normal file
26
docs/project-map/tests.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
module: tests
|
||||||
|
purpose: Unit-тесты (vitest) + моки
|
||||||
|
key_files:
|
||||||
|
- tests/__mocks__/$/index.ts — моки
|
||||||
|
- tests/audio.test.ts — тесты audio
|
||||||
|
- tests/config.test.ts — тесты config
|
||||||
|
- tests/insert.test.ts — тесты insert
|
||||||
|
- tests/keyboard.test.ts — тесты keyboard
|
||||||
|
- tests/transcribe.test.ts — тесты transcribe
|
||||||
|
dependencies: [src]
|
||||||
|
last_updated: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# tests/
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- `__mocks__/$/index.ts` — моки
|
||||||
|
- `audio.test.ts` — тесты audio
|
||||||
|
- `config.test.ts` — тесты config
|
||||||
|
- `insert.test.ts` — тесты insert
|
||||||
|
- `keyboard.test.ts` — тесты keyboard
|
||||||
|
- `transcribe.test.ts` — тесты transcribe
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
- vitest run, 47 тестов (5 файлов).
|
||||||
|
|
@ -6,8 +6,10 @@ const CONTAINER_CLASS = "ocvd-container";
|
||||||
const TIMER_CLASS = "ocvd-timer";
|
const TIMER_CLASS = "ocvd-timer";
|
||||||
const CANCEL_CLASS = "ocvd-cancel";
|
const CANCEL_CLASS = "ocvd-cancel";
|
||||||
const COMPOSER_SELECTORS = [
|
const COMPOSER_SELECTORS = [
|
||||||
'[data-component="session-composer"]',
|
'[data-component="prompt-input-v2"]',
|
||||||
|
'[data-component="session-prompt-dock"]',
|
||||||
'[data-component="session-new-composer"]',
|
'[data-component="session-new-composer"]',
|
||||||
|
'[data-component="session-composer"]',
|
||||||
];
|
];
|
||||||
const QUESTION_INPUT_SELECTOR = '[data-slot="question-custom-input"]';
|
const QUESTION_INPUT_SELECTOR = '[data-slot="question-custom-input"]';
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue