## Что сделано Фикс бага из issue #32: в child session (subagent) кнопка 🎤 появлялась над disabled-блоком "Prompt is disabled / Back to parent", а клик падал с toast "Could not find input field". - **`src/ui.ts` `findComposer()`** — добавлен guard: `session-prompt-dock` skip'ается в цикле `COMPOSER_SELECTORS`, если внутри него НЕТ `[data-component="prompt-input"]` или `[data-component="prompt-input-v2"]`. В child session внутри dock'а только disabled-блок — guard срабатывает, `findComposer()` возвращает `null`, кнопка не вставляется. - **`src/ui.ts` `injectIntoComposer()`** — defence-in-depth: ранний return, если в документе нет `[data-component="prompt-input"], [data-component="prompt-input-v2"]`. Страховка от любых future-случаев отсутствия реального composer (не только child session). - **Бамп `@version`** 1.0.2 → 1.0.3 синхронно в `package.json` и `vite.config.ts` — разблокировать автообновление userscript-менеджеров (ловушка PR #29 → #30). - **`tests/ui.test.ts`** (новый, 5 кейсов): dock с `prompt-input-v2` → кнопка есть; dock с `prompt-input` → кнопка есть; dock без composer (child session disabled-блок) → кнопки нет; пустой dock → кнопки нет; question-dock открыт → composer-кнопки нет (PR #31 regression guard). Тестирует через публичный `setupUI` + side-effect (`.ocvd-btn` в DOM). - **Handoff** `docs/handoff/pr-XX-child-session-disabled-composer.md` и **ADR 0004** `docs/decisions/0004-pr-XX-child-session-composer-guard.md` с placeholder'ом PR-номера (исправлю после получения номера). Это тот же класс бага, что и PR #31 (question-dock duplicate button) — `session-prompt-dock` использовался как composer-target когда реальный composer внутри не отрендерен. PR #31 пофиксил question-dock case, этот PR закрывает child-session case. ## Почему - **`session-prompt-dock` — общий wrapper для трёх состояний.** В `anomalyco/opencode` (`session-composer-region.tsx`) dock рендерится всегда когда `showComposer()` truthy (`!blocked() || !!parentID()` → в child session всегда truthy). Внутри условно: question-dock (PR #31), disabled-блок "Prompt is disabled / Back to parent" (child session, этот PR), или реальный composer. - **`findComposer()` выбирал wrapper.** `COMPOSER_SELECTORS` = [`prompt-input-v2`, `session-prompt-dock`, `session-new-composer`, `session-composer`] (ADR 0001). В child session `prompt-input-v2` отсутствует, `session-prompt-dock` присутствует. Guard PR #31 (skip если внутри `session-question-dock`) не срабатывал — внутри disabled-блок, не question-dock. - **Клик падал.** Кнопка вставлялась в dock через `injectIntoElement` (`position: absolute; top: 8px; right: 8px`). При клике → `insertIntoContenteditable()` → `querySelector('[data-component="prompt-input"]')` = `null` → toast "Could not find input field". - **Defence-in-depth.** Guard в `findComposer` (не возвращать dock без composer внутри) + guard в `injectIntoComposer` (не вставлять если в документе нет composer). Оба слоя независимы — любой один достаточно, второй страховка на race conditions. Аналог паттерна PR #31 / ADR 0003. Closes #32 Closes #32 --------- Co-authored-by: opencode-agent <agent@opencode.local> |
||
|---|---|---|
| .github | ||
| docs | ||
| src | ||
| tests | ||
| .gitignore | ||
| .nvmrc | ||
| biome.json | ||
| knip.json | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite-env.d.ts | ||
| vite.config.ts | ||
| vitest.config.ts | ||
OpenCode Voice Dictation / Голосовая диктовка для OpenCode
Русский
Голосовая диктовка для OpenCode web через Whisper (Groq API). Работает на ПК и телефоне.
⚠️ Требуется OpenCode web v1.18.x. В настройках OpenCode web включите «New UI» — в старом интерфейсе скрипт не работает. Совместимо с OpenCode v1.18.x; старые версии поддерживаются через fallback-селекторы.
Установка
Установить скрипт — открой ссылку в браузере с Violentmonkey/Tampermonkey и подтверди установку.
Или скачай с Releases и импортируй вручную.
Совместимость
| Платформа | Браузер | Менеджер скриптов | Статус |
|---|---|---|---|
| ПК | Vivaldi | Violentmonkey | ✅ |
| ПК | Chrome | Tampermonkey | ✅ |
| ПК | Firefox | Tampermonkey | ✅ |
| Android | Firefox | Tampermonkey | ✅ |
| Android | Vivaldi | — | ❌ Нет расширений |
| Android | Chrome | — | ❌ Нет расширений |
Настройка
- Получи бесплатный ключ на console.groq.com/keys
- Открой OpenCode web
- Меню Violentmonkey/Tampermonkey → Set Groq API Key → вставь
gsk_...
Использование
- Нажми кнопку микрофона 🎤 в правом верхнем углу поля ввода
- Говори — виден таймер записи и кнопка отмены
- Нажми ⏹ — запись остановится, текст вставится в поле ввода
- Или нажми ✕ — запись отменится, текст не вставляется
- На ПК: Ctrl+Space — горячая клавиша
Микрофон также доступен в поле ответа на вопросы OpenCode (когда выбираешь "ввести свой ответ").
Автообновление
Скрипт обновляется сам. При пуше в main CI собирает новую версию и публикует в ветку dist. Пользователи получают обновление автоматически.
Настройки
| Пункт меню | Описание |
|---|---|
| Set Groq API Key | Ключ gsk_... |
| Toggle Auto-Submit | Отправлять после транскрипции |
| Set Whisper Model | whisper-large-v3 или whisper-large-v3-turbo |
| Set Language | ru, en или пусто (авто) |
| Set Whisper Prompt | Контекст для точности |
English
Voice dictation for OpenCode web via Whisper (Groq API). Works on desktop and mobile.
⚠️ 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 Script — open this link in a browser with Violentmonkey/Tampermonkey and confirm installation.
Or download from Releases and import manually.
Compatibility
| Platform | Browser | Userscript Manager | Status |
|---|---|---|---|
| Desktop | Vivaldi | Violentmonkey | ✅ |
| Desktop | Chrome | Tampermonkey | ✅ |
| Desktop | Firefox | Tampermonkey | ✅ |
| Android | Firefox | Tampermonkey | ✅ |
| Android | Vivaldi | — | ❌ No extensions |
| Android | Chrome | — | ❌ No extensions |
Setup
- Get a free API key at console.groq.com/keys
- Open OpenCode web
- Violentmonkey/Tampermonkey menu → Set Groq API Key → paste
gsk_...
Usage
- Click the mic button 🎤 in the top-right corner of the input area
- Speak — recording timer and cancel button are displayed
- Click ⏹ — recording stops, transcribed text is inserted into the input
- Or click ✕ — recording is cancelled, no text inserted
- Desktop: Ctrl+Space shortcut
The mic button is also available in OpenCode question prompt answer fields (when choosing "type your own answer").
Auto-Update
The script updates automatically. When code is pushed to main, CI builds and publishes to the dist branch. Users receive updates automatically.
Settings
| Menu Item | Description |
|---|---|
| Set Groq API Key | API key gsk_... |
| Toggle Auto-Submit | Auto-send after transcription |
| Set Whisper Model | whisper-large-v3 or whisper-large-v3-turbo |
| Set Language | ru, en, or empty (auto-detect) |
| Set Whisper Prompt | Context for accuracy |
License
MIT — see LICENSE