fix(ui): broaden page gate + debug logging + version bump (#30)
## Что сделано - Расширен gate `isOpencodePage()` в `src/insert.ts`: теперь проверяет любой из 6 селекторов (`prompt-input`, `prompt-input-v2`, `session-prompt-dock`, `session-composer`, `session-new-composer`, `question-custom-input`) вместо одного `prompt-input`. Это активирует скрипт раньше на v1.18.x, где композер может монтироваться lazy. - Добавлено отладочное логирование с префиксом `[ocvd]` в `src/index.ts` (init, gate retry) и `src/ui.ts` (composer found/not found, mic button injected). Пользователь может видеть в DevTools Console где скрипт останавливается. - Бамп `@version` до `1.0.1` в `package.json` и `vite.config.ts` — разблокирует автообновление userscript-менеджеров (после PR #29 версия осталась `1.0.0`, автообновление не сработает). ## Почему PR #29 добавил корректные селекторы для v1.18.x, но пользователи не получили обновление из-за не-бампнутой `@version`. Также gate `isOpencodePage()` проверял только `prompt-input`, которого может не быть в DOM на ранних этапах lazy-mount. Добавление логирования поможет диагностировать runtime-проблемы в DevTools. Closes #28 --------- Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
parent
af5bc63bcc
commit
36169b4b08
7 changed files with 211 additions and 3 deletions
95
docs/decisions/0002-pr-30-broaden-page-detection-gate.md
Normal file
95
docs/decisions/0002-pr-30-broaden-page-detection-gate.md
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
# ADR 0002: Broaden page detection gate + debug logging + version bump for v1.18.x
|
||||||
|
|
||||||
|
- **Date**: 2026-07-24
|
||||||
|
- **PR**: #30
|
||||||
|
- **Parent PR**: #29
|
||||||
|
- **Issue**: #28
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
|
||||||
|
Accepted.
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
PR #29 исправил селекторы композера (`prompt-input-v2`, `session-prompt-dock`) для OpenCode web v1.18.x — live-браузер на opencode.slaid098.dev v1.18.3 подтвердил их корректность. Однако три пробела оставались:
|
||||||
|
|
||||||
|
1. **Gate `isOpencodePage()` проверял один селектор.** В `src/insert.ts` функция возвращала `document.querySelector('[data-component="prompt-input"]') !== null`. На v1.18.x `prompt-input` монтируется **lazy** — появляется асинхронно после загрузки сообщений сессии, внутри `session-prompt-dock`. В момент userscript `run-at: document-idle` ни `prompt-input`, ни `prompt-input-v2`, ни `session-prompt-dock` ещё не в DOM. `isOpencodePage()` возвращал `false`, `init()` уходил в `setTimeout(init, 1500)` и крутился в retry, задерживая инициализацию UI на 1.5s+ (а при медленной сети — дольше). Пользователь не видел, что скрипт вообще пытается.
|
||||||
|
|
||||||
|
2. **Нет отладочного логирования.** Все точки отказа были тихими: `isOpencodePage() === false`, `findComposer() === null`, успешный inject кнопки 🎤 — ни одно не писало в DevTools Console. Диагностика «скрипт не работает у пользователя» превращалась в гадание: загрузился ли userscript вообще? дошёл ли до gate? прошёл gate? нашёл композер? внедрил кнопку? Без логирования поддержке не за что зацепиться.
|
||||||
|
|
||||||
|
3. **`@version` осталась `1.0.0` после PR #29.** PR #29 менял код селекторов, но не бампал версию. Userscript-менеджеры (Violentmonkey, Tampermonkey) сравнивают `@version` из `.meta.js` (генерируется из `vite.config.ts` `userscript.version` через vite-plugin-monkey) — равные версии = нет автообновления. Пользователи оставались на сломанном билде PR #28, хотя исправление уже в репо.
|
||||||
|
|
||||||
|
Дополнительные ограничения:
|
||||||
|
- `oldInterfaceSunset = 2026-09-14` (`packages/app/src/context/settings.tsx:62`) — legacy UI окончательно уходит; селекторы `session-composer` / `session-new-composer` в gate будут мёртвым кодом после этой даты (общая pending-задача с ADR 0001).
|
||||||
|
- `run-at: document-idle` в `vite.config.ts` — userscript запускается после парсинга DOM, но до полного hydration SPA OpenCode. Lazy-mount композера — норма для SPA, не баг OpenCode.
|
||||||
|
- `match: ["*://*/*"]` — скрипт грузится на всех сайтах; gate должен отсеивать не-OpenCode страницы без побочных эффектов.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
**1. Расширить gate до 6 селекторов (любой = страница OpenCode с композером).** Добавить массив `PAGE_DETECT_SELECTORS` в `src/insert.ts`, `isOpencodePage()` проверяет через `Array.some()`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const PAGE_DETECT_SELECTORS = [
|
||||||
|
'[data-component="prompt-input"]',
|
||||||
|
'[data-component="prompt-input-v2"]',
|
||||||
|
'[data-component="session-prompt-dock"]',
|
||||||
|
'[data-component="session-composer"]',
|
||||||
|
'[data-component="session-new-composer"]',
|
||||||
|
'[data-slot="question-custom-input"]',
|
||||||
|
];
|
||||||
|
|
||||||
|
export function isOpencodePage(): boolean {
|
||||||
|
return PAGE_DETECT_SELECTORS.some((s) => document.querySelector(s) !== null);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Множественные селекторы ловят любой ранний маркер страницы OpenCode — `session-prompt-dock` монтируется раньше `prompt-input` в lifecycle v1.18.x, что сокращает задержку инициализации. `session-composer` / `session-new-composer` сохранены как fallback для pre-1.18 (до `oldInterfaceSunset`).
|
||||||
|
|
||||||
|
**2. Добавить `console.log` с префиксом `[ocvd]`** в ключевых точках lifecycle:
|
||||||
|
- `src/index.ts init()`: `[ocvd] OpenCode page not detected, retrying in 1.5s...` (retry) и `[ocvd] OpenCode page detected, setting up UI` (успех)
|
||||||
|
- `src/ui.ts findComposer()`: `[ocvd] Composer found via ${selector}` (какой селектор сработал) и `[ocvd] No composer found in DOM` (провал)
|
||||||
|
- `src/ui.ts injectIntoComposer()`: `[ocvd] Mic button injected into composer` (успех inject)
|
||||||
|
|
||||||
|
Единый префикс `[ocvd]` = grep-маркер в DevTools Console. Пять точек покрывают весь путь: gate retry → gate success → composer search → composer found/miss → button inject.
|
||||||
|
|
||||||
|
**3. Бамп `@version` до `1.0.1` в обоих source-of-truth:**
|
||||||
|
- `package.json` `"version": "1.0.1"` (npm/semver)
|
||||||
|
- `vite.config.ts` `userscript.version: "1.0.1"` (vite-plugin-monkey → `.meta.js` → userscript-менеджеры)
|
||||||
|
|
||||||
|
Синхронный бамп обоих файлов обязателен: vite-plugin-monkey берёт `@version` только из `vite.config.ts`, `package.json` на userscript-менеджеры не влияет.
|
||||||
|
|
||||||
|
## Альтернативы
|
||||||
|
|
||||||
|
### 1. Ждать lazy-mount `prompt-input` без расширения gate
|
||||||
|
- **Плюс**: минимальная правка, gate остаётся на одном селекторе.
|
||||||
|
- **Минус**: на v1.18.x `prompt-input` монтируется последним в цепочке (`session-prompt-dock` → `prompt-input-v2` → `prompt-input` contenteditable). Gate на одном `prompt-input` добавляет +1.5s+ задержки инициализации на каждый retry-цикл, на медленной сети — кратно больше. Пользователь видит пустой композер без кнопки 🎤 дольше необходимого.
|
||||||
|
|
||||||
|
### 2. MutationObserver для gate вместо polling
|
||||||
|
- **Плюс**: реактивность — `isOpencodePage()` срабатывает в момент появления любого селектора, без retry-цикла 1500ms.
|
||||||
|
- **Минус**: сложнее. Требует переделки `init()` с polling на observer, обработки disconnect, аккуратной работы с re-mount (SPA-навигация между сессиями). Текущий polling 1500ms достаточно лёгкий и понятный; переход на observer — отдельная задача с тестами. Для PR #30 (hotfix) избыточно.
|
||||||
|
|
||||||
|
### 3. Single source of truth для `@version` через `process.env.npm_package_version`
|
||||||
|
- **Плюс**: бамп только `package.json`, `vite.config.ts` читает версию через `process.env.npm_package_version` (vite подставляет автоматически). Исключает рассинхрон.
|
||||||
|
- **Минус**: требует тестов на сборку (verify, что `userscript.version` в `.meta.js` реально подставился из env), возможны edge-cases с vite-plugin-monkey (плагин может требовать строковый литерал в schema). Отложено — не blocking для PR #30, кандидат на отдельный PR с тестами.
|
||||||
|
|
||||||
|
### 4. Вынести логирование под флаг `GM_getValue("debug")`
|
||||||
|
- **Плюс**: production-билд чистый, логи только для диагностики.
|
||||||
|
- **Минус**: лишний `GM_getValue`-вызов на каждый лог, плюс пользователь не сможет включить логи без знания меню Violentmonkey. Для PR #30 (диагностика после ряда жалоб) важнее «логи видны всегда» — флаг откладывается до момента, когда логи станут шумом.
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
|
||||||
|
- Gate `isOpencodePage()` проходит на любой странице, где присутствует хотя бы один из 6 селекторов — задержка инициализации на v1.18.x сокращается (ранний маркер `session-prompt-dock` ловится раньше `prompt-input`).
|
||||||
|
- DevTools Console содержит трассу `[ocvd]` от gate до inject — диагностика «скрипт не работает» сводится к grep `[ocvd]` в Console.
|
||||||
|
- `@version` 1.0.1 в `.meta.js` разблокирует автообновление userscript-менеджеров — пользователи получают исправление PR #29 + PR #30 одним обновлением.
|
||||||
|
- Логирование `[ocvd]` остаётся в production-билде (vite-plugin-monkey не дропает `console.log`); если станет шумом — убрать или вынести под флаг.
|
||||||
|
- `PAGE_DETECT_SELECTORS` и `COMPOSER_SELECTORS` (ADR 0001) частично перекрываются, но служат разным целям: gate (`some()`, порядок не важен) vs composer-find (`for...of`, порядок = приоритет). Не объединять.
|
||||||
|
- После `oldInterfaceSunset` (14.09.2026) legacy-селекторы `session-composer` / `session-new-composer` в `PAGE_DETECT_SELECTORS` станут мёртвым кодом — удалить вместе с cleanup из ADR 0001.
|
||||||
|
|
||||||
|
## Источники
|
||||||
|
|
||||||
|
- `src/insert.ts` (текущий): `PAGE_DETECT_SELECTORS`, `isOpencodePage()`
|
||||||
|
- `src/index.ts` (текущий): `init()`, логирование gate
|
||||||
|
- `src/ui.ts` (текущий): `findComposer()`, `injectIntoComposer()`, логирование composer
|
||||||
|
- `vite.config.ts` (текущий): `userscript.version`, `run-at: document-idle`
|
||||||
|
- Предыдущий ADR: `docs/decisions/0001-pr-29-v1-18-composer-selectors-fallback-order.md` (порядок `COMPOSER_SELECTORS`, `oldInterfaceSunset`)
|
||||||
|
- Память: `technical/opencode-web-ui-composer-selectors-1.18.4.md` (lazy-mount композера на v1.18.x)
|
||||||
100
docs/handoff/pr-30-v1-18-runtime-gate-debug.md
Normal file
100
docs/handoff/pr-30-v1-18-runtime-gate-debug.md
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
---
|
||||||
|
pr_number: 30
|
||||||
|
branch: fix/ui/v1-18-runtime-gate-debug
|
||||||
|
parent_pr: 29
|
||||||
|
title: broaden page gate + debug logging + version bump for v1.18.x
|
||||||
|
status: open
|
||||||
|
created: 2026-07-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# Handoff — PR #30: v1.18.x runtime gate + debug logging + version bump
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
PR #29 (`fix/ui): support OpenCode 1.18.x composer selectors`) добавил корректные селекторы `prompt-input-v2` и `session-prompt-dock` в массив `COMPOSER_SELECTORS` — live-браузер на opencode.slaid098.dev v1.18.3 подтвердил их валидность. Однако PR #29 оставил три пробела, из-за которых скрипт всё ещё не запускался у реальных пользователей:
|
||||||
|
|
||||||
|
1. **`@version` не бампнута.** В `package.json` и `vite.config.ts` осталась `1.0.0` (та же, что у PR #29). Userscript-менеджеры (Violentmonkey/Tampermonkey) сравнивают `@version` из `.meta.js` для автообновления — совпадение версий = нет обновления = пользователи остаются на сломанном билде PR #28.
|
||||||
|
2. **Gate `isOpencodePage()` узкий.** В `src/insert.ts` функция проверяла только `[data-component="prompt-input"]`. На v1.18.x композер монтируется lazy (после загрузки сообщений сессии), а `prompt-input` в `PAGE_DETECT_SELECTORS` стоит первым — но в момент `document-idle` run-at ни один из 6 селекторов может ещё не быть в DOM. Скрипт уходил в retry каждые 1500ms и пользователь не понимал, запустился ли он вообще.
|
||||||
|
3. **Нет отладочного логирования.** Все точки отказа (`isOpencodePage() === false`, `findComposer() === null`, успешный inject) были тихими — в DevTools Console ничего не появлялось, диагностика «скрипт не работает» превращалась в гадание.
|
||||||
|
|
||||||
|
Issue: #28 (родительский). PR #30 — продолжение без новой issue.
|
||||||
|
|
||||||
|
## Что сделано
|
||||||
|
|
||||||
|
Три коммита на ветке `fix/ui/v1-18-runtime-gate-debug`:
|
||||||
|
|
||||||
|
- **`d5f80e7` fix(ui): broaden page detection gate for v1.18.x** — `src/insert.ts`: добавлен массив `PAGE_DETECT_SELECTORS` из 6 селекторов, `isOpencodePage()` теперь возвращает `true` при совпадении любого (через `.some()`). Расширение с 1 селектора (`prompt-input`) до 6 (`prompt-input`, `prompt-input-v2`, `session-prompt-dock`, `session-composer`, `session-new-composer`, `question-custom-input`).
|
||||||
|
- **`6982bfb` feat(ui): add debug logging for init and composer detection** — `src/index.ts` (2 строки в `init()`) + `src/ui.ts` (3 строки в `findComposer()` / `injectIntoComposer()`): `console.log` с унифицированным префиксом `[ocvd]` в каждой ключевой точке lifecycle.
|
||||||
|
- **`af3edc7` chore: bump version to 1.0.1** — `package.json` и `vite.config.ts`: `1.0.0` → `1.0.1` в обоих файлах (синхронно).
|
||||||
|
|
||||||
|
## Почему
|
||||||
|
|
||||||
|
- **`@version` не бампнута в PR #29.** Userscript-менеджеры не подтягивают изменения, если `@version` в `.meta.js` не выросла. PR #29 менял код селекторов, но не трогал версию — пользователи получали «обновление недоступно», хотя код был исправлен. PR #30 бампает версию в обоих source-of-truth (`package.json` для npm, `vite.config.ts` userscript.version для vite-plugin-monkey).
|
||||||
|
- **Gate проверял только `prompt-input`.** На v1.18.x `prompt-input` монтируется lazy внутри `session-prompt-dock` после hydration сессии. В момент `document-idle` run-at элемента ещё нет, `isOpencodePage()` возвращает `false`, `init()` уходит в `setTimeout(init, 1500)` и крутится до тех пор, пока композер не появится. С 6 селекторами `some()` ловит любой ранний маркер страницы OpenCode (`session-prompt-dock` монтируется раньше `prompt-input`).
|
||||||
|
- **Нет логирования для диагностики.** Без `console.log` пользователь не мог отличить «скрипт не загрузился» от «скрипт загрузился, но gate не прошёл» от «скрипт загрузился, gate прошёл, но композер не найден». Префикс `[ocvd]` даёт единый grep-маркер в DevTools Console.
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
- После merge проверить live на opencode.slaid098.dev v1.18.3: открыть DevTools Console, обновить страницу с установленным userscript 1.0.1 — должны появиться `[ocvd] OpenCode page detected, setting up UI` → `[ocvd] Composer found via [data-component="prompt-input-v2"]` → `[ocvd] Mic button injected into composer`. Если вместо `detected` крутится `not detected, retrying in 1.5s...` — gate недостаточен, расширять `PAGE_DETECT_SELECTORS` дальше.
|
||||||
|
- Подтвердить, что userscript-менеджеры подтянули автообновление: сравнить `@version` в `about:` для установленного скрипта с `1.0.1`. Если менеджер не видит обновление — проверить, что `updateURL` в `vite.config.ts` указывает на свежий `.meta.js` в ветке `dist/` (или `main` после merge).
|
||||||
|
- После `oldInterfaceSunset` (2026-09-14) legacy-селекторы `session-composer` / `session-new-composer` в `PAGE_DETECT_SELECTORS` и `COMPOSER_SELECTORS` станут мёртвым кодом — удалить отдельным PR (общая задача с PR #29 pending).
|
||||||
|
- Логирование `[ocvd]` остаётся в production: если после стабилизации появится шум в Console пользователей — вынести под флаг `GM_getValue("debug")` или убрать полностью.
|
||||||
|
|
||||||
|
## Watch out
|
||||||
|
|
||||||
|
- **vite-plugin-monkey берёт `@version` из `vite.config.ts` `userscript.version`, НЕ из `package.json`.** `package.json.version` нужен только для npm/semver-инструментов. Рассинхрон = бамп одного файла → userscript-менеджеры не видят обновления, хотя npm видит. PR #30 бампает оба синхронно, но в будущем это ловушка — кандидат на single source of truth через `process.env.npm_package_version` (см. ADR 0002, альтернатива 3).
|
||||||
|
- **Логирование `[ocvd]` останется в production-билде.** `vite-plugin-monkey` не вырезает `console.log` по умолчанию. Все 5 точек (`index.ts:177,181`, `ui.ts:254,258,306`) попадут в `.user.js`. Не забывать убирать если будет шум, либо включать `terser` drop_console.
|
||||||
|
- **Порядок `PAGE_DETECT_SELECTORS` не имеет семантического значения** (в отличие от `COMPOSER_SELECTORS`, где порядок = приоритет): `some()` возвращает `true` по первому совпадению, gate только решает «страница OpenCode или нет». Не путать с `COMPOSER_SELECTORS` из ADR 0001, где порядок критичен.
|
||||||
|
- **`src/insert.ts` `PROMPT_INPUT_SELECTOR` (одиночный) не удалён** — он используется `insertIntoContenteditable()` для фактической вставки текста, не для gate. Не объединять с `PAGE_DETECT_SELECTORS`.
|
||||||
|
- **Retry `setTimeout(init, 1500)` не имеет backoff/лимита** — если страница никогда не станет OpenCode (false match на стороннем сайте), скрипт крутится бесконечно. На текущем `match: ["*://*/*"]` это потенциальная утечка таймера; вне scope PR #30, но отметить на будущее.
|
||||||
|
|
||||||
|
## Изменения
|
||||||
|
|
||||||
|
### `src/insert.ts`
|
||||||
|
- Добавлен массив `PAGE_DETECT_SELECTORS` (6 селекторов):
|
||||||
|
```ts
|
||||||
|
const PAGE_DETECT_SELECTORS = [
|
||||||
|
'[data-component="prompt-input"]',
|
||||||
|
'[data-component="prompt-input-v2"]',
|
||||||
|
'[data-component="session-prompt-dock"]',
|
||||||
|
'[data-component="session-composer"]',
|
||||||
|
'[data-component="session-new-composer"]',
|
||||||
|
'[data-slot="question-custom-input"]',
|
||||||
|
];
|
||||||
|
```
|
||||||
|
- `isOpencodePage()` изменён с `document.querySelector(PROMPT_INPUT_SELECTOR) !== null` на `PAGE_DETECT_SELECTORS.some((s) => document.querySelector(s) !== null)`.
|
||||||
|
- `PROMPT_INPUT_SELECTOR`, `SUBMIT_SELECTOR`, `QUESTION_INPUT_SELECTOR` — без изменений (используются `insertIntoContenteditable` / `submitPrompt` / `isQuestionPromptOpen`).
|
||||||
|
|
||||||
|
### `src/index.ts`
|
||||||
|
- `init()`: добавлены 2 `console.log` — `[ocvd] OpenCode page not detected, retrying in 1.5s...` (ветка retry) и `[ocvd] OpenCode page detected, setting up UI` (ветка успеха).
|
||||||
|
|
||||||
|
### `src/ui.ts`
|
||||||
|
- `findComposer()`: добавлен `console.log(\`[ocvd] Composer found via ${selector}\`)` при совпадении и `[ocvd] No composer found in DOM` при провале.
|
||||||
|
- `injectIntoComposer()`: добавлен `[ocvd] Mic button injected into composer` после успешного inject.
|
||||||
|
|
||||||
|
### `package.json`
|
||||||
|
- `"version": "1.0.0"` → `"version": "1.0.1"`.
|
||||||
|
|
||||||
|
### `vite.config.ts`
|
||||||
|
- `userscript.version: "1.0.0"` → `"1.0.1"`.
|
||||||
|
|
||||||
|
### Файлы вне спеки
|
||||||
|
- `src/audio.ts`, `src/transcribe.ts`, `src/config.ts`, `src/keyboard.ts`, `src/types.ts` — без изменений.
|
||||||
|
|
||||||
|
## Коммиты
|
||||||
|
|
||||||
|
1. `d5f80e7` fix(ui): broaden page detection gate for v1.18.x — `src/insert.ts`
|
||||||
|
2. `6982bfb` feat(ui): add debug logging for init and composer detection — `src/index.ts`, `src/ui.ts`
|
||||||
|
3. `af3edc7` chore: bump version to 1.0.1 — `package.json`, `vite.config.ts`
|
||||||
|
4. `docs(handoff): add handoff + ADR for PR #30` — этот коммит
|
||||||
|
|
||||||
|
## ADR
|
||||||
|
|
||||||
|
См. `docs/decisions/0002-pr-30-broaden-page-detection-gate.md`.
|
||||||
|
|
||||||
|
## Источники
|
||||||
|
|
||||||
|
- Предыдущий handoff: `docs/handoff/pr-29-v1-18-composer-selectors.md` (родительский PR, селекторы v1.18.x)
|
||||||
|
- Предыдущий ADR: `docs/decisions/0001-pr-29-v1-18-composer-selectors-fallback-order.md` (порядок `COMPOSER_SELECTORS`)
|
||||||
|
- Память: `technical/opencode-web-ui-composer-selectors-1.18.4.md` (исследование `sst/opencode` main, lazy-mount композера)
|
||||||
|
- Live-верификация: opencode.slaid098.dev v1.18.3 (DevTools, confirm селекторов v1.18.x)
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "opencode-voice-dictation",
|
"name": "opencode-voice-dictation",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
||||||
|
|
@ -174,9 +174,11 @@ function checkFirstRun(): void {
|
||||||
|
|
||||||
function init(): void {
|
function init(): void {
|
||||||
if (!isOpencodePage()) {
|
if (!isOpencodePage()) {
|
||||||
|
console.log("[ocvd] OpenCode page not detected, retrying in 1.5s...");
|
||||||
setTimeout(init, 1500);
|
setTimeout(init, 1500);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("[ocvd] OpenCode page detected, setting up UI");
|
||||||
|
|
||||||
ui = setupUI({
|
ui = setupUI({
|
||||||
onToggle: (target: InsertTarget) => {
|
onToggle: (target: InsertTarget) => {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
const PROMPT_INPUT_SELECTOR = '[data-component="prompt-input"]';
|
const PROMPT_INPUT_SELECTOR = '[data-component="prompt-input"]';
|
||||||
const SUBMIT_SELECTOR = '[data-action="prompt-submit"]';
|
const SUBMIT_SELECTOR = '[data-action="prompt-submit"]';
|
||||||
const QUESTION_INPUT_SELECTOR = '[data-slot="question-custom-input"]';
|
const QUESTION_INPUT_SELECTOR = '[data-slot="question-custom-input"]';
|
||||||
|
const PAGE_DETECT_SELECTORS = [
|
||||||
|
'[data-component="prompt-input"]',
|
||||||
|
'[data-component="prompt-input-v2"]',
|
||||||
|
'[data-component="session-prompt-dock"]',
|
||||||
|
'[data-component="session-composer"]',
|
||||||
|
'[data-component="session-new-composer"]',
|
||||||
|
'[data-slot="question-custom-input"]',
|
||||||
|
];
|
||||||
|
|
||||||
export type InsertTarget = "composer" | "question";
|
export type InsertTarget = "composer" | "question";
|
||||||
|
|
||||||
export function isOpencodePage(): boolean {
|
export function isOpencodePage(): boolean {
|
||||||
return document.querySelector(PROMPT_INPUT_SELECTOR) !== null;
|
return PAGE_DETECT_SELECTORS.some((s) => document.querySelector(s) !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isQuestionPromptOpen(): boolean {
|
export function isQuestionPromptOpen(): boolean {
|
||||||
|
|
|
||||||
|
|
@ -251,9 +251,11 @@ function findComposer(): HTMLElement | null {
|
||||||
for (const selector of COMPOSER_SELECTORS) {
|
for (const selector of COMPOSER_SELECTORS) {
|
||||||
const el = document.querySelector<HTMLElement>(selector);
|
const el = document.querySelector<HTMLElement>(selector);
|
||||||
if (el) {
|
if (el) {
|
||||||
|
console.log(`[ocvd] Composer found via ${selector}`);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log("[ocvd] No composer found in DOM");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,6 +303,7 @@ function injectIntoComposer(onToggle: (target: InsertTarget) => void, onCancel:
|
||||||
const composer = findComposer();
|
const composer = findComposer();
|
||||||
if (composer) {
|
if (composer) {
|
||||||
injectIntoElement(composer, onToggle, onCancel, "composer");
|
injectIntoElement(composer, onToggle, onCancel, "composer");
|
||||||
|
console.log("[ocvd] Mic button injected into composer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export default defineConfig({
|
||||||
userscript: {
|
userscript: {
|
||||||
name: "OpenCode Voice Dictation",
|
name: "OpenCode Voice Dictation",
|
||||||
namespace: "https://github.com/slaid098/opencode-voice-dictation",
|
namespace: "https://github.com/slaid098/opencode-voice-dictation",
|
||||||
version: "1.0.0",
|
version: "1.0.1",
|
||||||
description:
|
description:
|
||||||
"Voice dictation for OpenCode web using Whisper (Groq API) - works on PC and mobile",
|
"Voice dictation for OpenCode web using Whisper (Groq API) - works on PC and mobile",
|
||||||
author: "slaid098",
|
author: "slaid098",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue