12 KiB
УВАГА: Термінал агента не працює. Не виконуй жодних команд (dotnet build, dotnet restore, dotnet run, встановлення NuGet-пакетів тощо) самостійно. Якщо для задачі щось треба встановити, оновити чи запустити — напиши це явним окремим пунктом "Потрібно виконати вручну:" в кінці відповіді для цієї задачі, і не намагайся обійти це через bash/термінал.
Реалізуй дві задачі в FoxBrowser. Роби послідовно, кожну — окремим описом, що змінено і як перевірити вручну (агент працює в Linux sandbox без dotnet/WPF runtime — фінальний тест виконує користувач на Windows).
1. Діагностика й виправлення кнопки "Розширення"
Кнопка налаштувань розширень (ExtensionsSettingsWindow) працює
неправильно. Перевір по черзі всі гіпотези нижче, знайди реальну причину
в коді (не вигадуй, яка з них правильна, — прочитай файли й перевір),
і виправ саме те, що підтвердиться. Якщо підтвердиться кілька — виправ усі.
1a. Recovery-fallback environment без AreBrowserExtensionsEnabled
- Знайти в
MainWindow/TabManagerвесь код навколо recovery-гілки зNEXT_AGENT_GUIDE/інструкції ("Startup recovery fix — 0x8007139F") — місце, де при HRESULT0x8007139Fстворюється запаснийCoreWebView2Environmentз тимчасовою user-data folder. - Перевірити: чи цей запасний environment створюється через ту саму
функцію/той самий
CoreWebView2EnvironmentOptionsзAreBrowserExtensionsEnabled = true, що й основний, чи через окремий шматок коду, де цей прапорець забули виставити. - Якщо прапорець не потрапляє в recovery-гілку — винести створення
CoreWebView2EnvironmentOptionsв один спільний метод/константу, яку використовують і основний, і recovery шлях, щоб розбіжність стала неможливою в принципі, а не просто додати прапорець ще раз у другому місці. - Додати явний лог/статус (напр. поле
bool ExtensionsAvailableна TabManager чи MainWindow), який ExtensionsSettingsWindow може прочитати при відкритті — і якщоfalse(бо стартанули в recovery-режимі), показати користувачу зрозуміле повідомлення в самому вікні ("Розширення недоступні в цьому сеансі — застосунок запустився в режимі відновлення профілю, перезапусти FoxBrowser"), а не порожній список без пояснень.
1b. IsEnabled read-only і биндинг чекбокса
- Знайти XAML розмітку списку розширень в
ExtensionsSettingsWindow.xaml. - Перевірити: чи
IsCheckedчекбокса прив'язаний напряму двостороннім біндингом доExtension.IsEnabled(read-only властивість), чи черезChecked/Uncheckedevent-обробник (або Command), що явно викликаєawait extension.EnableAsync(bool). - Якщо це прямий
TwoWay-біндинг на read-only властивість — замінити наOneWay-біндинг для відображення поточного стану + окремийClick/Checked/Uncheckedобробник, який викликаєEnableAsync(), чекає результат, і тільки після успіху оновлює UI-стан (checkbox), а при помилці — повертає checkbox у попередній стан і показує повідомлення.
1c. FolderBrowserDialog без owner-вікна
- Знайти виклик
FolderBrowserDialog/OpenFileDialogдля "Додати розширення" вExtensionsSettingsWindow.xaml.cs. - Перевірити, чи передається owner-handle:
new System.Windows.Interop.WindowInteropHelper(this).HandleчерезIWin32Window-обгортку (WinForms-діалог вимагаєIWin32Window, не голийIntPtr— якщо ще нема обгортки-хелпера, додати простийNativeWindowWrapper : IWin32Window). - Якщо owner не передається — додати, щоб діалог відкривався поверх
ExtensionsSettingsWindow, а не міг ховатись позаду.
1d. Options-сторінка розширення через спільний WebView2
- Знайти обробник кнопки "Налаштування" (per-extension), що відкриває
chrome-extension://<id>/options.html. - Перевірити: чи ця навігація йде через ТОЙ САМИЙ спільний
CoreWebView2, яким керуєTabManagerдля звичайних вкладок, чи через окремийCoreWebView2Controller, створений безпосередньо вExtensionsSettingsWindow. - Якщо використовується спільний контрол — це помилка архітектури: клік
по "Налаштування" в діалозі може непомітно перекидати активну вкладку
користувача в головному вікні. Виправити: створити в
ExtensionsSettingsWindowвласний ізольованийCoreWebView2Controller(з того самогоCoreWebView2Environment, щоб профіль/розширення збігались) — тільки для options-сторінок, ніколи не займаючи головний спільний WebView2.
Після кожного виправленого пункту (1a-1d) — короткий підсумок і ручний тест-сценарій для Windows.
2. Звук WebView2 у Volume Mixer як "FoxBrowser"
Додати Core/AudioSessionLabeler.cs, який перейменовує WASAPI
audio-сесії власних дочірніх WebView2-процесів на "FoxBrowser" з іконкою
застосунку, БЕЗ ризику торкнутись чужих WebView2-сесій (Teams, Outlook,
системний Edge).
- Додати NuGet-пакет
NAudio(зазнач це явно в "Потрібно виконати вручну" — сам пакет не встановлюй, тільки допиши<PackageReference>в.csprojвручну і попроси користувача зробитиdotnet restore). - Клас має:
- Відстежувати список PID усіх дочірніх
msedgewebview2.exe-процесів, які належать саме FoxBrowser (ті самі, що вже прив'язані через Job Object з попередньої задачі про дерево процесів — переюзати ту логіку, не дублювати). - Через
NAudio.CoreAudioApi.MMDeviceEnumeratorотримати default render endpoint (eRender,eMultimedia), і йогоAudioSessionManager. - Підписатись на подію нової сесії (
AudioSessionManager.SessionCreatedв NAudio, або еквівалентIAudioSessionNotification.OnSessionCreatedякщо в NAudio такого немає в потрібній версії — перевір API конкретної версії пакету, яку додаси). - У обробнику нової сесії: якщо
session.GetProcessIDвходить у список PID FoxBrowser — викликатиsession.DisplayName = "FoxBrowser"іsession.IconPath = Path.Combine(AppContext.BaseDirectory, "foxbrowser.ico")(або еквівалентні NAudio-методиSetDisplayNameAsync/властивості — перевір актуальний API пакету). - Критично: ці властивості НЕ переживають життя об'єкта сесії (задокументована поведінка WASAPI) — тому одноразового виклику при старті недостатньо. Логіка з пункту 3-4 має спрацьовувати на КОЖНУ нову сесію протягом усього часу роботи FoxBrowser, не тільки на старті.
- НІКОЛИ не застосовувати
DisplayName/IconPathдо сесії, чий PID не входить у явно відстежуваний список власних дочірніх процесів — це і є захист від зачіпання чужихmsedgewebview2.exeна машині користувача.
- Відстежувати список PID усіх дочірніх
- Покласти файл
foxbrowser.icoв корінь проєкту поруч з іншими іконками (якщо такого файлу ще нема в репозиторії — створи заглушку-примітивну іконку і явно напиши користувачу в "Потрібно виконати вручну", що варто замінити на нормальну). - Викликати ініціалізацію
AudioSessionLabelerодин раз при старті застосунку (напр. вMainWindowпісля успішної ініціалізаціїTabManager, коли вже відомий перший дочірній PID).
Ручний тест Windows:
- Запустити FoxBrowser, відкрити вкладку з YouTube, почати відтворення.
- Відкрити Volume Mixer (правий клік на іконку гучності в треї Windows → Open Volume mixer, або через Settings → System → Sound → Volume mixer).
- Перевірити, що застосунок у списку показаний як "FoxBrowser" з іконкою застосунку, а не як "Microsoft Edge WebView2"/msedgewebview2.exe.
- Переключитись на іншу вкладку, знову увімкнути звук на новій — перевірити, що лейбл лишається "FoxBrowser" і для нової audio-сесії (не тільки для першої).
- Паралельно запустити щось інше з WebView2 на цій же машині (напр. Microsoft Teams, якщо є), перевірити, що ЙОГО лейбл у Volume Mixer НЕ змінився і лишився своїм — це підтверджує, що фільтр по PID працює правильно й не займає чужі процеси.