fix(deploy): restore namespace and register menu commands at top-level #4
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
Зачем: после миграции с GitHub на Forgejo (PR#3) у пользователя появилось ДВА скрипта в Tampermonkey вместо одного. Причина:
@namespaceбыл сменён сhttps://github.com/slaid098/opencode-voice-dictationнаhttps://git.slaid098.dev/...— Tampermonkey/Violentmonkey идентифицируют скрипт по паре@name+@namespace(Greasemonkey-стандарт). Смена namespace = новый скрипт, не обновление. Дополнительно: 7 menu-команд (Set Groq API Keyи др.) регистрируются только послеisOpencodePage()→true(src/index.ts:227внутриinit()после gateindex.ts:207-211). На не-OpenCode странице меню пустое (только Edit/Delete) — пользователь не может настроить скрипт сразу после установки.Контекст:
@namespace— это идентификатор скрипта (строка-ID для дедупликации), НЕ функциональный URL. Userscript-менеджеры НЕ резолвят его как URL. Менять его при миграции хоста = сломать идентификацию → дубликаты.@updateURL/@downloadURL/@icon— функциональные URL, их смена на Forgejo (PR#3) правильна и работает.GM_registerMenuCommand) вsrc/config.ts:49-55вызываются изregisterMenuCommands()(src/index.ts:227-235), который находится ВНУТРИinit()ПОСЛЕ gateisOpencodePage()(index.ts:207-211). На не-OpenCode странице gate возвращаетfalse→init()уходит вsetTimeout(init, 1500)retry →registerMenuCommands()не вызывается → меню пустое.promptForApiKey,promptForEndpoint, и др.) используютGM_setValue(работает на любой странице) +ui?.toast(...)(optional chaining — no-op еслиuiещёnull). Безопасно регистрировать на top-level.Задача
1.
vite.config.ts:10— вернуть старый@namespace(идентификатор, не URL)namespace: "https://git.slaid098.dev/slaid098/opencode-voice-dictation"→namespace: "https://github.com/slaid098/opencode-voice-dictation"@updateURL/@downloadURL/@iconНЕ трогать — они уже на Forgejo (PR#3, рабочие).2. Version bump 1.0.6 → 1.0.7 (СИНХРОННО)
vite.config.ts:11:version: "1.0.6"→version: "1.0.7"package.json:3:"version": "1.0.6"→"version": "1.0.7"@updateURLна GitHub) не автоапдейтнется, но при ручной переустановке по ссылке из README (с@namespace= старый) Tampermonkey предложит «обновить» существующий 1.0.4 → 1.0.7, без дубликата.3.
src/index.ts— вынестиregisterMenuCommands()из gate на top-levelregisterMenuCommands({...})вызывается внутриinit()на строках 227-235, ПОСЛЕ gateisOpencodePage()(строки 207-211).registerMenuCommands({...})с теми же callback-аргументами на top-level, ДО вызоваinit()(т.е. между определениемinit()на строке 206 и вызовомinit()на строке 240 — или прямо передinit()вызовом).registerMenuCommands({...})из телаinit()(строки 227-235).init():setupUI,setupKeyboardShortcut,checkFirstRun— они зависят от OpenCode DOM /ui.promptForApiKey,toggleAutoSubmit,promptForModel,promptForLanguage,promptForWhisperPrompt,promptForEndpoint,promptForTemperature) — проверить что они в scope на top-level. Если ониfunctiondeclarations — hoisted, ОК. Еслиconst/let— должны быть определены до вызова. Прочитать файл и убедиться.ui?.toast(...)в callbacks — optional chaining, no-op еслиuiещёnull(до gate).GM_setValueработает на любой странице. Безопасно.4.
AGENTS.md— добавить правило про@namespaceВ секцию
## Userscript metadata(или создать после## @icon) добавить:Контракты
@name+@namespace= уникальный ID скрипта в Tampermonkey/Violentmonkey/Greasemonkey. Совпадение пары = «обновить существующий», несовпадение = «новый скрипт».@namespaceНЕ резолвится как URL — это opaque string (исторически URL по конвенции, но менеджеры НЕ делают HTTP-запрос к нему).GM_registerMenuCommandрегистрирует команду в меню Tampermonkey popup. Работает на любой странице (не зависит от DOM). Доступна если@grant GM_registerMenuCommand(есть,vite.config.ts:16).GM_setValue/GM_getValue— persistent storage, работает на любой странице.vite.config.tsиpackage.jsonобязаны совпадать (AGENTS.md## Version bump).Инварианты
@connect *НЕ сужать (AGENTS.md## @connect).@updateURL/@downloadURL/@iconостаются на Forgejo (PR#3, рабочие) — НЕ откатывать на GitHub.COMPOSER_SELECTORSпорядок НЕ менять (ADR 0001–0004).assets/icon.pngНЕ удалять, путь НЕ менять.whisperPromptdefault""НЕ трогать (ADR-0007).setupUI/setupKeyboardShortcut/checkFirstRunостаются ВНУТРИinit()после gate — они зависят от OpenCode DOM.docs/decisions/**.Граничные случаи
@updateURL(raw.githubusercontent.com → 404) НЕ автоапдейтнется. Пользователь должен один раз перейти по install-ссылке из README → TM предложит «обновить» (namespace совпадёт) → 1.0.4 → 1.0.7, без дубликата. После этого новый@updateURL(Forgejo) заработает для будущих автоапдейтов.GM_setValueсработает (config сохранится),ui?.toastno-op (нет UI). Пользователь не увидит подтверждения, но значение сохранится. При переходе на OpenCode страницу сохранённый config подхватится. Это приемлемо — лучше чем вообще не иметь доступа к настройкам вне OpenCode.promptForApiKeyи др.) —const/letи определены ниже top-level вызова: переместить вызовregisterMenuCommandsпосле их определений. Прочитатьsrc/index.tsи проверить.Влияние на связанные компоненты
src/config.ts— без изменений (registerMenuCommandsfunction definition не трогается, только call site вindex.ts).src/insert.ts— без изменений (isOpencodePage()gate остаётся дляsetupUI/setupKeyboardShortcut/checkFirstRun).vite.config.ts— толькоnamespace(строка 10) +version(строка 11).@updateURL/@downloadURL/@icon/@connectНЕ трогать.package.json— толькоversion(строка 3).AGENTS.md— добавить секцию## @namespace.Вне scope
setupUI/checkFirstRunиз gate (они зависят от DOM, оставляются)docs/**init()(отдельная задача, noted в memory gotchas)Критерии приемки
vite.config.ts:10—namespace=https://github.com/slaid098/opencode-voice-dictation(старый, как ID)vite.config.ts:11+package.json:3=1.0.7(синхронно)vite.config.ts—@updateURL/@downloadURL/@iconостаются на Forgejo (НЕ откатаны)src/index.ts—registerMenuCommands({...})вызывается на top-level (доinit()), НЕ внутриinit()после gatesrc/index.ts—setupUI/setupKeyboardShortcut/checkFirstRunостаются внутриinit()после gateAGENTS.md— добавлена секция## @namespaceс правилом про идентификаторnpm run lint→ passnpm run typecheck→ passnpm run test→ passnpm run build→dist/opencode-voice-dictation.user.jsheader содержит@namespace https://github.com/slaid098/...+@version 1.0.7+@updateURL https://git.slaid098.dev/...@connect *остался (не сужен)