Запись 63. Первый боевой краш-тест на Arch Linux, расследование зависания Omni-Search и интеграция GitHub MCP
⏱️ Время: 10 октября 2026, 23:10 — 11 октября 2026, 01:15 (~2 часа)1. Повод: семейный баг-репорт из мира Arch Linux
Самые строгие и честные тестировщики — это близкие люди, особенно если они заядлые линуксоиды. Мой сын установил свежую сборку Shellit на свою рабочую станцию под управлением Arch Linux с тайлинговым композитором Hyprland (Wayland) и практически сразу завел первый официальный GitHub Issue в репозитории проекта:
«[Bug]: Split layout freeze / OpenGL frame timeout via Omni-search Ctrl+K in Linux GTK/OpenGL»
Сценарий воспроизведения ошибки был предельно лаконичен: открываешь командную палитру через Ctrl+K, быстро вводишь команду переключения сетки сплитов (например, split 2x2 или split horizontal) и нажимаешь Enter. Если нажать клавишу быстро или отправить повторный ввод, окно терминала намертво замирало, а в консоль высыпался стек GTK: glXSwapBuffers timeout / eglSwapBuffers failure и Flutter engine frame request timed out waiting for OpenGL fence.
Вдобавок он подметил еще несколько тонких шероховатостей повседневного опыта:
- При запуске локального терминала со стартового окна окружение иногда стартовало в
sh, а иногда вbash, хотя в системе основным шеллом настроенzsh. В выпадающем меню выбора оболочки красовались дубликатыZSHиZSH. - Шрифты: стандартные моноширинные начертания без патчей Nerd Fonts некорректно отображали иконки файлов при работе с современными утилитами вроде
ezaилиstarship. - Запрос на будущее: графические терминальные протоколы (Kitty Graphics / Sixel) для просмотра картинок прямо в консоли.
2. Подключение GitHub MCP и раскопки дефекта BUG-056
Первым делом мы связали нашу среду разработки с GitHub напрямую через протокол MCP (Model Context Protocol). Теперь ИИ-ассистент видит тикеты, обсуждения и пулл-реквесты репозитория в реальном времени, может отвечать в тредах и сопровождать жизненный цикл каждой проблемы. Мы получили Issue #1, зафиксировали в баг-трекере BUG-056 (P0) и начали хирургический разбор.
Что выяснилось при анализе цепочки событий:
- Каскадная мутация состояния в модальном окне:
Вomni_search_modal.dartпри нажатииEnterвызывался метод действияaction.onSelect(), который синхронно дергал Riverpod-провайдер смены макетаupdateSplitLayout(). И только после этого вызывалсяNavigator.of(context).pop().
В Linux Wayland/OpenGL движок GTK в момент закрытия всплывающего окна производит синхронизацию кадровых буферов. Когда одновременно с разрушением модального окна в соседнем поддереве начиналась полная пересборка сетки терминалов, графический контекст получал два конфликтующих запроса на смену поверхностей, что приводило к сбою OpenGL fence. - Уничтожение поддерева терминала составным ключом
ValueKey:
Вshellit_app_shell.dartвиджетSplitMatrixViewмонтировался с ключом видаValueKey('${tab.id}-${tab.splitLayout.name}'). Из-за включения имени раскладки в составной ключ Flutter при каждой смене сплита полностью уничтожал существующее дерево виджетов терминала и создавал его с нуля вместо вызова мягкого методаdidUpdateWidget. - Шторм ресайзов PTY-потока:
Внутриterminal_screen.dartпри перестройке макета виджетTerminalViewмгновенно менял габариты, вызывая шквал колбэковonResize(до 4–6 вызовов за кадр) с отправкой пакетов изменения размера псевдотерминала в сокет.
3. Логика решений: стабилизация графического конвейера и порядок в Linux-шеллах
Мы устранили первопричины комплексно:
- Однократный барьер и отложенное исполнение действий Omni-Search:
Ввели атомарный флаг_isExecutingAction. По первому нажатию Enter поле поиска немедленно блокирует повторный ввод, фокус отключается, модальное окно закрывается черезNavigator.of(context).pop(), а сама смена состояния в Riverpod откладывается на следующий кадр черезWidgetsBinding.instance.addPostFrameCallback. - Стабильный ключ сплит-матрицы:
КлючSplitMatrixViewзакреплен за идентификатором вкладки:ValueKey('split-${tab.id}'). Теперь переключение между одиночным экраном, вертикальным/горизонтальным сплитом и матрицей 2x2 проходит через естественный жизненный циклdidUpdateWidget, сохраняя память терминала и контроллеры ввода. - Мемоизация размеров терминала:
Добавлен метод_safeResizeTerminalс защитой от повторных синхронизаций: если количество столбцов и строк не изменилось, паразитный вызовresize()в сокет и PTY полностью отсекается. - Умное сканирование оболочек на Linux:
ВLocalShellDetectorдобавили разрешение символических ссылок черезresolveSymbolicLinksSync(). На дистрибутивах вроде Arch Linux с объединенным каталогом/usr-mergeпути/bin/zshи/usr/bin/zshтеперь распознаются как один и тот же бинарник, исключая дубли в меню.
Если приложение запущено из меню композитора Wayland без экспортированной переменной$SHELL, детектор безопасно обращается к/etc/passwdдля текущего пользователя и применяет естественный приоритет:пользовательский шелл > zsh > bash > fish > sh.
4. Результат
- Баг
BUG-056полностью решен и верифицирован автоматическим регрессионным тестомomni_bar_shortcut_test.dart. - Все 203 теста пакета
packages/terminal_uiи 61 тест основного приложенияapps/shellitзавершились с безупречным зеленым статусом. - Добавили файл
.nojekyllи привели в порядок фронтматтер аналитики в веб-портале, защитив автоматические сборки GitHub Actions от сбоев. - Сформулировали и внесли в долгосрочный бэклог инициативы
IDEA-037(пользовательские Nerd Fonts) иIDEA-038(графические протоколы Kitty/Sixel). - Опубликовали подробный технический отчет в ветке GitHub Issue #1.