v0.9.4 Linux Wayland & GTK OpenGL Stability 9 мин 10–11 октября 2026, 23:10 — 01:15

Акт XV: Первый боевой краш-тест на Arch Linux — почему зависали сплиты при быстром вводе в Omni-search и как мы подружили Shellit с Wayland и GitHub MCP

Как первый публичный Issue #1 от сына-линуксоида вскрыл конфликт OpenGL/Wayland при быстрой смене сплит-раскладки через Ctrl+K, как подключение GitHub MCP позволило вести отладку в реальном времени, и как мы навели порядок в обнаружении Linux-оболочек.

BUG-056 #linux #wayland #hyprland #opengl #gtk #omni-search #github-mcp #bug-056 #splits #local-shells
Контекст акта: Когда проект выходит на стадию стабильного бета-тестирования, главным испытанием становится встреча с реальными рабочими окружениями пользователей. Наш первый публичный краш-тест пришел прямо из семьи: запуск свежей сборки Shellit на рабочей машине под управлением Arch Linux с тайлинговым композитором Hyprland обернулся зависанием интерфейса при быстром переключении сплитов через командную строку Ctrl+K. Мы связали среду разработки с GitHub через Model Context Protocol (MCP), декомпозировали дефект BUG-056 и устранили гонку кадровых буферов OpenGL, попутно решив вопрос с дубликатами шеллов в Linux.

Запись 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.

Вдобавок он подметил еще несколько тонких шероховатостей повседневного опыта:

  1. При запуске локального терминала со стартового окна окружение иногда стартовало в sh, а иногда в bash, хотя в системе основным шеллом настроен zsh. В выпадающем меню выбора оболочки красовались дубликаты ZSH и ZSH.
  2. Шрифты: стандартные моноширинные начертания без патчей Nerd Fonts некорректно отображали иконки файлов при работе с современными утилитами вроде eza или starship.
  3. Запрос на будущее: графические терминальные протоколы (Kitty Graphics / Sixel) для просмотра картинок прямо в консоли.

2. Подключение GitHub MCP и раскопки дефекта BUG-056

Первым делом мы связали нашу среду разработки с GitHub напрямую через протокол MCP (Model Context Protocol). Теперь ИИ-ассистент видит тикеты, обсуждения и пулл-реквесты репозитория в реальном времени, может отвечать в тредах и сопровождать жизненный цикл каждой проблемы. Мы получили Issue #1, зафиксировали в баг-трекере BUG-056 (P0) и начали хирургический разбор.

Что выяснилось при анализе цепочки событий:

  1. Каскадная мутация состояния в модальном окне:
    В omni_search_modal.dart при нажатии Enter вызывался метод действия action.onSelect(), который синхронно дергал Riverpod-провайдер смены макета updateSplitLayout(). И только после этого вызывался Navigator.of(context).pop().
    В Linux Wayland/OpenGL движок GTK в момент закрытия всплывающего окна производит синхронизацию кадровых буферов. Когда одновременно с разрушением модального окна в соседнем поддереве начиналась полная пересборка сетки терминалов, графический контекст получал два конфликтующих запроса на смену поверхностей, что приводило к сбою OpenGL fence.
  2. Уничтожение поддерева терминала составным ключом ValueKey:
    В shellit_app_shell.dart виджет SplitMatrixView монтировался с ключом вида ValueKey('${tab.id}-${tab.splitLayout.name}'). Из-за включения имени раскладки в составной ключ Flutter при каждой смене сплита полностью уничтожал существующее дерево виджетов терминала и создавал его с нуля вместо вызова мягкого метода didUpdateWidget.
  3. Шторм ресайзов PTY-потока:
    Внутри terminal_screen.dart при перестройке макета виджет TerminalView мгновенно менял габариты, вызывая шквал колбэков onResize (до 4–6 вызовов за кадр) с отправкой пакетов изменения размера псевдотерминала в сокет.

3. Логика решений: стабилизация графического конвейера и порядок в Linux-шеллах

Мы устранили первопричины комплексно:

  1. Однократный барьер и отложенное исполнение действий Omni-Search:
    Ввели атомарный флаг _isExecutingAction. По первому нажатию Enter поле поиска немедленно блокирует повторный ввод, фокус отключается, модальное окно закрывается через Navigator.of(context).pop(), а сама смена состояния в Riverpod откладывается на следующий кадр через WidgetsBinding.instance.addPostFrameCallback.
  2. Стабильный ключ сплит-матрицы:
    Ключ SplitMatrixView закреплен за идентификатором вкладки: ValueKey('split-${tab.id}'). Теперь переключение между одиночным экраном, вертикальным/горизонтальным сплитом и матрицей 2x2 проходит через естественный жизненный цикл didUpdateWidget, сохраняя память терминала и контроллеры ввода.
  3. Мемоизация размеров терминала:
    Добавлен метод _safeResizeTerminal с защитой от повторных синхронизаций: если количество столбцов и строк не изменилось, паразитный вызов resize() в сокет и PTY полностью отсекается.
  4. Умное сканирование оболочек на 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.
📖 Типографика статьи выровнена по алгоритму Кнута — Пласса с помощью mcp-typography-server на базе Justif.
Knuth-Plass • TeX Style