Release v1.5.6
Downloads
macOS (Universal) - Supports both Apple Silicon and Intel
Option 1: Installation Script (Recommended)
Install with a single command (version v1.5.6):
curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v1.5.6The script will:
- Download the release archive
- Extract and install to
/Applications/ - Fix macOS quarantine attributes and permissions
- Launch the application automatically
Option 2: Manual Installation
- Download:
singbox-launcher-v1.5.6-macos.zip - Extract the ZIP file
- Remove quarantine attribute (required):
xattr -cr "singbox-launcher.app" && chmod +x "singbox-launcher.app/Contents/MacOS/singbox-launcher"
- Double-click
singbox-launcher.appto run- If macOS blocks the app, go to System Settings → Privacy & Security and click "Open Anyway"
- Alternatively, right-click the app and select "Open" (first time only)
Windows (amd64)
- Download:
singbox-launcher-v1.5.6-win64.zip- or
singbox-launcher-v1.5.6-win64-full.zip— full bundle:sing-box.exe,wintun.dll, the config template and Mesa3D (mesa3d/, used only when no hardware OpenGL — RDP, VMs) are already inside, nothing is downloaded on first launch
- or
- Extract the ZIP file to a folder, for example:
C:\Program Files\singbox-launcher\ - Run
singbox-launcher.exefrom that folder- You may need administrator rights to install to Program Files
- The regular archive downloads
sing-boxandwintun.dllon first launch
Windows 7 (x86, legacy)
- Download:
singbox-launcher-v1.5.6-win7-32.zip - Extract the ZIP file to a folder and run
singbox-launcher-win7-32.exe- For Windows 7 / 32-bit or legacy compatibility only
Linux Support
⚠️ Linux build temporarily unavailable - мы ищем тестировщика для ручного тестирования перед включением автоматической сборки.
Checksums
See checksums.txt for SHA256 checksums of all files.
Release notes — v1.5.6
EN
Highlights
-
The launcher can be a Tailscale node. Add server → Tailscale asks for an auth key and, optionally, a control URL, hostname, exit node and the ephemeral / accept-routes switches — and adds not just the node but everything it needs to be useful: a MagicDNS server for
*.ts.netand a route rule for100.64.0.0/10, carried with the node as its own config fragments. Tailnet names resolve and tailnet hosts are reachable right after Rebuild, with no hand-written JSON on three separate tabs. Atailscalenode pasted as sing-box JSON is imported the same way instead of being rejected as an unknown type, and the DNS tab now editstailscaleservers with a form. Each node gets its own state directory (bin/tailscale/<tag>), so a second tailnet node does not overwrite the first one's identity. The key is one-off: it is consumed at first login, and from then on the identity lives in that directory — delete it and the tailnet registers a new device. A tailnet node is offered in a Direction only when it has an exit node: without one it opens the tailnet, not the internet. -
A node can now carry the config fragments it needs. Some servers are useless on their own: a WireGuard endpoint with subnets behind the peer needs a DNS server bound to it, a DNS rule for its domains and a route rule for its subnets. Paste a whole sing-box config with exactly one node into Add and the launcher keeps that bundle with the node instead of dropping
dns/routeas it used to; the node's JSON tab shows and edits it as a document, with@self(and@{self}inside a longer string) standing for the node's own tag so the bundle survives a rename. What the node carries are ordinary launcher entries: each route rule gets its own draggable row in the rules list, named after the rule and the node, with its own toggle and its own place in the order — bodies are edited on the node, so the rows have no gear or delete button. Its DNS server and DNS rule show up read-only at the end of the DNS tab. Disable the node and none of it reaches the config. -
AmneziaWG obfuscation is now editable on an existing node. Open a WireGuard node in Sources and the Settings tab carries an obfuscation block right below Detour: the masquerade domain and browser (
id/ib) plus the junk countersjc/jmin/jmax. Until now those fields only ever arrived with the import — a server that started demanding obfuscation after the node was created meant going back to the provider for a fresh link. Edits are written into the node as you type. The block is hidden when a detour is set, because a node dialled through another outbound raises no transport of its own: choosing a detour clears the fields from the node, and a node that arrives carrying both shows a warning instead of the form. The masquerade protocol is fixed toquic;s1-s4andh1-h4are never written, since any value there other than the WireGuard default stops the server from recognising the handshake. -
AmneziaWG 3.0/3.1 servers import as they are. Amnezia now hands out AWG 3.x profiles, and until now the launcher quietly threw away everything the new protocol adds: header protection, content padding, random trailers, cookie suppression and the ranged timings. The node looked fully configured and the handshake could never succeed. A
vpn://profile, a pasted.confand awireguard://link now all carry those fields through to the config, along with two details the export keeps outside the[Interface]block: the MTU (read fromlast_config.mtuand clamped to the AmneziaWG ceiling of 1280 like any other AmneziaWG node) and the real DNS addresses behind Amnezia's$PRIMARY_DNS/$SECONDARY_DNSplaceholders. The server list labels such a nodewireguard·awg3orwireguard·awg3.1. This needs core1.14.0-lx.32; on an older core the node is dropped with a build-report line that names the version you have and the one you need, instead of the whole config being rejected.
Fixes
-
Mesa3D installed itself on machines with a working GPU and killed the launcher (#125). In the
win64-fullarchive the Mesa DLLs ship next to the exe, and the gate copied them in without ever asking: any failure of the OpenGL probe — including "the driver did not answer within 10 seconds" — was read as "this machine has no hardware OpenGL". A probe that times out on a home PC is a temporary driver hiccup, not a verdict, and the copy made things worse rather than better: Mesa was never pinned to a driver, so on a machine with a GPU it pickedd3d12, the very stack that had just hung, and the process died a second after the window appeared. Nothing was left to debug with — no Go panic, socrash.logstayed empty, and the window build has no stderr at all, so whatever the driver printed vanished. There was also no way back: the switch to software rendering was invisible in the UI and irreversible without knowing which file to delete. Now the gate distinguishes a timeout from a refusal and offers Retry / Ignore / Abort; Mesa is never installed without an explicit Yes in a dialog;GALLIUM_DRIVER=llvmpipeis pinned before Mesa loads (unless you set that variable yourself) and the installed DLLs are verified by a second probe that loads them by full path — if they do not come up as llvmpipe, the install is rolled back on the spot. What renders the window is now recorded inbin/gl-state.json, together with whether the previous start ever reached a frame: a start that died under Mesa while hardware OpenGL works is offered a switch back on the next launch, every Mesa start says so in the log, the Diagnostics tab has a button to toggle the renderer either way (the DLLs are renamed to.off, never deleted), and native output from Mesa, drivers and GLFW now lands inlogs/native-stderr.loginstead of nowhere. With-trayno dialog is shown and no file is touched. Switching the renderer now restarts the launcher for you:OPENGL32.dllsits in the exe's import table, so Windows maps it before any of the launcher's own code runs and the renderer simply cannot change inside a live process — the first release candidate answered "yes, disable Mesa", carried on with Mesa still mapped and crashed a second time. For the same reason the hardware probe now moves the localopengl32.dllaside while it runs, and discards any "hardware" answer whose GL vendor turns out to be Mesa; previously it reported Mesa'sD3D12 (NVIDIA GeForce GT 440)as if it were the GPU itself. -
macOS: the file picker greys out every file (#120). On macOS 26 the native open panel no longer understands a bare extension as a type filter, so Import… on the Settings tab and Add from file showed the backup and config files disabled and there was nothing to select. The launcher now resolves each extension to a system type identifier before opening the panel; extensions without a registered type (
.vpn,.conf) get a dynamic one, which the panel accepts. If nothing resolves, the panel opens without a filter rather than empty. -
Backup import lost the routing rules and the default direction (#111). The import report counted the file's rules as applied, but only preset rules reached the Rules tab: user and rule-set rules were written to the canonical list while the wizard kept reading its previous view of them.
route.finalfrom the file went into a field the wizard never reads, so the Default direction stayed as it was, and the launcher's own export never wroteroute.finalat all. Both channels are now the ones the wizard actually uses. -
A drag-and-drop reorder could leave the whole window deaf to clicks. The insertion line drawn while dragging a row (Sources, Rules, DNS, Directions, folder contents) lives in the canvas overlay stack, and it was removed as "whatever is on top". If anything else had landed on top mid-drag, the wrong overlay was removed and the line's wrapper stayed behind forever — and Fyne routes every click to the top overlay only, so the window kept rendering but ignored all input while the process was perfectly alive (two freezes on 7–8 September, both needing a restart). The wrapper is now removed by identity, anything above it is put back, and every drag end and every list rebuild clears it.
-
REALITY nodes stopped working against updated servers, silently. Xray v26.9.8 tightened its REALITY handshake: the server now wants a post-quantum key share in the ClientHello, and among the uTLS fingerprints only the Chrome ones send it. A node whose link said
fp=firefox— orfp=safari,ios,android,edge,360,qq— was answered by the decoy site instead of the proxy, so the connection looked established and simply carried nothing: no error in the log, nothing forsing-box checkto catch. The defaultrandompicked a dead fingerprint four times out of five, which is why the same node worked one evening and not the next. The launcher now uses a Chrome fingerprint whenever it emits a REALITY block, leaving the link's own value visible on the node and flagging the substitution in the build report. Nodes whose servers are still on an older Xray are unaffected — a Chrome ClientHello is accepted by both. -
An SRS rule keeps every rule-set it was given. A rule built from several SRS URLs used to keep only the first one: the state record held a single URL, so after the Configurator was reopened the other sets were gone, and the build emitted just the first set even in the session that created the rule (reported against 1.5.5). The record now carries the full list: the rule restores all of its sets, the build emits one local rule-set per URL and a single route rule that references them all, and the orphan cleanup keeps every downloaded file. Backups carry the whole list too, as
refsnext to the existingref(a draft contract field, so an app that does not know it still gets the first set, as before).
Technical / Internal
-
A
tailscalenode on a core without the tag is dropped, not fatal. The endpoint exists only in cores built withwith_tailscale(the fork from1.14.0-lx.31), and a single such node makessing-box checkreject the whole config — every other server included. The launcher probes the core's build tags once per build and drops those nodes with a warning that names the cause in the build report, exactly as it already does fornaive. An unreadablesing-box versionstill counts as "supported": nodes are never dropped on guesswork. -
The AmneziaWG 3.x gate is a version gate, not a tag gate.
with_awghas been in the core for years, butheader_protection_keyand its neighbours only landed in1.14.0-lx.32, and an older core rejects the whole config as invalid JSON rather than the one node it cannot read. The launcher therefore reads both the build tags and the version fromsing-box versiononce per build: nowith_awg→ no AmneziaWG at all; base version above 1.14.0 → supported; exactly 1.14.0 → the-lx.Nrelease number decides. Unreadable output still counts as "supported" — nodes are never dropped on guesswork. The MTU rule is unchanged: an AWG 3.x node is clamped to 1280 like any AmneziaWG endpoint — on the reference server the export's own1376carried no data, 1280 did. -
A pasted wg-quick config no longer loses its masquerade silently. The INI reader carried the junk numbers and the explicit
i1-i5tags but skippedip/id/ib, so a config with masquerade looked fully configured while its first decoy packet went out undisguised. The same sugar now also counts as an AmneziaWG marker on its own, which clamps such a node's MTU to the AmneziaWG ceiling — without that, the endpoint fails the silent way: the handshake completes and no data flows. -
GET /debug/goroutines— a goroutine dump without killing the launcher. When the Fyne UI freezes, the Go side usually keeps running: the debug API answers and the hourly heartbeat still logs. Until now there was no way to see what the main loop was waiting on: the launcher's stderr goes to/dev/nullwhen started from Finder, so a SIGQUIT dump is lost, and anlldbattach kills the process outright. The new endpoint returns the same text Go prints on SIGQUIT — every goroutine's stack astext/plain,X-Goroutinesheader with the count — while the process keeps running.goroutine 1is the Fyne/GLFW main loop. Take the dump before restarting a frozen launcher. -
GET /debug/uiandPOST /debug/ui/overlays/clear— see and clear the overlay stack. The snapshot lists each window's canvas size, focused widget and overlay stack (type, position, size, children), which is exactly where a stale overlay shows up; the clear call drops every overlay and gives the window back without a restart.504 ui loop unresponsivemeans the Fyne main loop itself is blocked, which is a different bug. Capabilityuiin the manifest.
RU
Основное
-
Лаунчер умеет быть узлом Tailscale. Add server → Tailscale спрашивает auth key и, по желанию, control URL, hostname, exit node и галки ephemeral / accept routes — и заводит не только узел, но и всё, без чего он бесполезен: MagicDNS-сервер на
*.ts.netи правило маршрута на100.64.0.0/10, которые едут вместе с узлом его собственными фрагментами конфига. Имена tailnet резолвятся, а хосты доступны сразу после Rebuild, без ручного JSON на трёх вкладках. Узелtailscale, вставленный sing-box-конфигом, теперь импортируется так же, а не отвергается как неизвестный тип; DNS-сервер типаtailscaleвкладка DNS правит формой. У каждого узла свой каталог состояния (bin/tailscale/<тег>) — второй узел tailnet не затирает идентичность первого. Ключ одноразовый: расходуется при первом входе, дальше идентичность живёт в этом каталоге, и его удаление регистрирует в tailnet новое устройство. В Направление узел tailnet предлагается только с указанным exit node: без него он открывает саму tailnet, а не выход в интернет. -
Узел может нести с собой фрагменты конфига, без которых он не работает. Некоторые серверы бесполезны в одиночку: WireGuard-endpoint с подсетями за пиром требует привязанного к нему DNS-сервера, DNS-правила на его домены и правила маршрута на его подсети. Вставьте в Add целый sing-box-конфиг ровно с одним узлом — лаунчер сохранит эту связку вместе с узлом, а не выбросит
dns/route, как раньше; вкладка JSON узла показывает и правит её документом, где@self(и@{self}внутри строки) означает собственный тег узла, так что связка переживает переименование. То, что несёт узел, — обычные записи лаунчера: каждое правило маршрута встаёт в списке правил своей перетаскиваемой строкой с именем правила и узла, со своим тумблером и своим местом в порядке; тела правятся у узла, поэтому у строк нет ни шестерёнки, ни удаления. DNS-сервер и DNS-правило видны только для чтения в конце вкладки DNS. Узел выключен — в конфиг не попадает ничего из этого. -
Обфускация AmneziaWG правится у уже заведённого узла. Откройте WireGuard-узел в Sources — на вкладке Settings сразу под Detour появился блок обфускации: домен и браузер маскировки (
id/ib) плюс junk-числаjc/jmin/jmax. Раньше эти поля приезжали только с импортом, и сервер, начавший требовать обфускацию после заведения узла, отправлял пользователя к провайдеру за новой ссылкой. Правки пишутся в узел по мере ввода. При выбранном detour блок скрыт: узел, ходящий через чужой outbound, своего транспорта не поднимает — назначенный detour снимает поля с узла, а узел, приехавший сразу с обоими, показывает предупреждение вместо формы. Протокол маскировки закреплён какquic;s1–s4иh1–h4не пишутся вовсе, потому что любое значение там, кроме дефолтного для WireGuard, лишает сервер возможности узнать рукопожатие. -
Серверы AmneziaWG 3.0/3.1 импортируются как есть. Amnezia раздаёт профили AWG 3.x, а лаунчер до сих пор молча выбрасывал всё, что добавляет новый протокол: защиту заголовка, добивку содержимого, случайные хвосты, подавление cookie и диапазонные тайминги. Узел выглядел полностью настроенным, а рукопожатие не могло пройти никогда. Профиль
vpn://, вставленный.confи ссылкаwireguard://теперь доносят эти поля до конфига — вместе с двумя вещами, которые экспорт держит вне блока[Interface]: MTU (читается изlast_config.mtuи ужимается до потолка AmneziaWG 1280, как у любого узла AmneziaWG) и настоящие адреса DNS за плейсхолдерами Amnezia$PRIMARY_DNS/$SECONDARY_DNS. В списке серверов такой узел подписанwireguard·awg3илиwireguard·awg3.1. Нужно ядро1.14.0-lx.32: на более старом узел снимается со строкой в отчёте сборки, называющей и вашу версию, и требуемую, — вместо того чтобы ядро отвергло весь конфиг целиком.
Исправления
-
Mesa3D ставилась сама на машины с исправной видеокартой и убивала лаунчер (#125). В архиве
win64-fullDLL Mesa лежат рядом с exe, и гейт копировал их вообще без вопроса: любая неудача пробы OpenGL — включая «драйвер не ответил за 10 секунд» — читалась как «аппаратного OpenGL на этой машине нет». На домашнем ПК зависшая проба означает временную икоту драйвера, а не приговор, и копия делала только хуже: драйвер Mesa никто не пинил, поэтому на машине с видеокартой она уходила вd3d12— тот самый стек, который только что завис, — и процесс умирал через секунду после появления окна. Отлаживать было нечем: паники Go не было, значитcrash.logоставался пустым, а у оконной сборки нет stderr, и всё, что печатал драйвер, пропадало. Пути назад тоже не было: переход на программный рендеринг никак не отражался в UI и не откатывался, если не знать, какой файл удалить. Теперь гейт отличает таймаут от отказа и предлагает Retry / Ignore / Abort; Mesa не ставится без явного «Yes» в диалоге; перед загрузкой Mesa пинитсяGALLIUM_DRIVER=llvmpipe(если вы не задали переменную сами), а поставленные DLL проверяются второй пробой, которая грузит их по полному пути — не поднялись как llvmpipe, установка тут же откатывается. Чем рисуется окно, теперь записано вbin/gl-state.jsonвместе с тем, дошёл ли прошлый старт до кадра: старту, умершему под Mesa при живом железе, на следующем запуске предложат вернуться обратно, каждый старт через Mesa пишет об этом в лог, на вкладке Диагностика появилась кнопка переключения рендерера в обе стороны (DLL переименовываются в.off, а не удаляются), а нативный вывод Mesa, драйверов и GLFW попадает вlogs/native-stderr.log, а не в никуда. С флагом-trayне показывается ни один диалог и не трогается ни один файл. Смена рендерера теперь перезапускает лаунчер сама:OPENGL32.dllстоит в таблице импорта exe, Windows отображает его раньше любой строки нашего кода, и внутри живого процесса рендерер не сменить в принципе — первый RC на ответ «да, отключить Mesa» продолжал старт с уже отображённой Mesa и падал второй раз подряд. По той же причине проба железа теперь уводит локальныйopengl32.dllв сторону на время своей работы и отбрасывает «аппаратный» ответ, у которого вендор GL оказался Mesa: раньше она выдавала мезовскийD3D12 (NVIDIA GeForce GT 440)за саму видеокарту. -
macOS: диалог выбора файла серит все файлы (#120). На macOS 26 системная панель открытия перестала понимать голое расширение как фильтр типа, и Import… на вкладке Settings вместе с Add from file показывали файлы бэкапов и конфигов недоступными — выбрать было нечего. Теперь лаунчер перед открытием панели резолвит каждое расширение в системный идентификатор типа; расширения без зарегистрированного типа (
.vpn,.conf) получают динамический, который панель принимает. Если не резолвится ничего, панель открывается без фильтра, а не пустой. -
Импорт бэкапа терял правила маршрутизации и Направление по умолчанию (#111). Отчёт импорта считал правила из файла применёнными, но до вкладки Rules доходили только пресетные: пользовательские и srs-правила писались в канонический список, а визард продолжал читать свой прежний вид этого списка.
route.finalиз файла уходил в поле, которое визард не читает, и Default direction оставалось прежним; собственный экспорт лаунчераroute.finalне писал вовсе. Оба канала теперь те, которыми визард действительно пользуется. -
Перетаскивание строки могло оставить всё окно глухим к кликам. Линия вставки, которая рисуется при перетаскивании строки (Sources, Rules, DNS, Направления, состав папки), живёт в стеке overlay-ев канваса, а снималась как «верхний, кто бы он ни был». Если посреди броска поверх неё успевало лечь что-то ещё, снималось оно, а обёртка линии оставалась навсегда — Fyne же отдаёт любой клик только верхнему overlay-у, так что окно продолжало рисоваться, но не реагировало на ввод при полностью живом процессе (два фриза 7–8 сентября, оба лечились перезапуском). Теперь обёртка снимается по ссылке, лежавшее поверх возвращается на место, а любое завершение броска и любая пересборка списка её убирают.
-
Узлы REALITY молча переставали работать на обновившихся серверах. Xray v26.9.8 ужесточил рукопожатие REALITY: сервер теперь ждёт в ClientHello постквантовый ключевой обмен, а из отпечатков uTLS его шлют только chrome-овские. Узлу, у которого в ссылке стояло
fp=firefox— илиfp=safari,ios,android,edge,360,qq, — отвечал камуфляжный сайт вместо прокси: соединение выглядело установленным и просто не везло ничего. Ни ошибки в логе, ни повода придраться уsing-box check. Дефолтныйrandomвыбирал мёртвый отпечаток в четырёх случаях из пяти — отсюда и «вчера работало, сегодня нет» на одном и том же узле. Теперь везде, где лаунчер эмитит блок REALITY, он использует chrome-отпечаток; значение из ссылки остаётся видно на узле, а подмена отмечается строкой в отчёте сборки. Узлов, чьи серверы остались на старом Xray, это не касается — chrome-овский ClientHello принимают и те, и другие. -
SRS-правило хранит все наборы, которые ему дали. Правило, собранное из нескольких ссылок на SRS, запоминало только первую: запись состояния держала один URL, поэтому после переоткрытия Конфигуратора остальные наборы исчезали, а сборка эмитила лишь первый набор даже в той сессии, где правило создали (репорт по 1.5.5). Теперь запись несёт полный список: правило восстанавливает все наборы, сборка эмитит по локальному rule-set на каждую ссылку и одно правило маршрута со ссылкой на все, а чистка сирот держит каждый скачанный файл. Бэкап тоже переносит весь список — полем
refsрядом с прежнимref(черновое поле контракта: приложение, которое его не знает, по-прежнему получает первый набор).
Техническое / Внутреннее
-
Узел
tailscaleна ядре без тега снимается, а не валит сборку. Endpoint есть только в ядрах, собранных сwith_tailscale(форк с1.14.0-lx.31), и один такой узел заставляетsing-box checkотвергнуть конфиг целиком — вместе со всеми остальными серверами. Лаунчер один раз за сборку опрашивает теги ядра и снимает такие узлы с предупреждением, называющим причину в отчёте сборки, — ровно как уже делает дляnaive. Нечитаемый выводsing-box versionпо-прежнему считается «умеет»: узлы не снимаются по догадке. -
Гейт AmneziaWG 3.x — по версии, а не по тегу.
with_awgесть в ядре давно, ноheader_protection_keyи соседи появились только в1.14.0-lx.32, и ядро постарше отвергает как невалидный JSON весь конфиг, а не тот единственный узел, который не смогло прочитать. Поэтому лаунчер раз за сборку читает изsing-box versionи теги, и версию: нетwith_awg→ AmneziaWG нет вовсе; базовая версия выше 1.14.0 → умеет; ровно 1.14.0 → решает номер релиза в суффиксе-lx.N. Нечитаемый вывод по-прежнему считается «умеет»: узлы не снимаются по догадке. Правило MTU не меняется: узел AWG 3.x ужимается до 1280, как любой endpoint AmneziaWG — на эталонном сервере1376из экспорта данных не давал, 1280 дал. -
Вставленный wg-quick конфиг больше не теряет маскировку молча. Разбор INI переносил junk-числа и явные теги
i1–i5, но пропускалip/id/ib: конфиг с маскировкой выглядел полностью настроенным, а первый decoy-пакет уходил без неё. Тот же сахар теперь сам по себе считается признаком AmneziaWG, из-за чего MTU такого узла ужимается до потолка AmneziaWG — без этого узел отказывает молча: рукопожатие проходит, данные не идут. -
GET /debug/goroutines— дамп горутин без убийства лаунчера. Когда UI Fyne замирает, Go-часть обычно продолжает жить: debug API отвечает, часовой heartbeat пишется в лог. Увидеть, на чём стоит главный цикл, до сих пор было нечем: stderr лаунчера при запуске из Finder уходит в/dev/null, так что дамп по SIGQUIT теряется, а attach черезlldbпроцесс просто убивает. Новый эндпоинт отдаёт тот же текст, что Go печатает по SIGQUIT, — стеки всех горутин какtext/plain, число в заголовкеX-Goroutines— не останавливая процесс.goroutine 1— главный цикл Fyne/GLFW. Снимать дамп нужно до перезапуска зависшего лаунчера. -
GET /debug/uiиPOST /debug/ui/overlays/clear— посмотреть и снять стек overlay-ев. Снимок перечисляет по каждому окну размер канваса, виджет в фокусе и стек overlay-ев (тип, позиция, размер, дети) — ровно то место, где виден забытый overlay; очистка снимает все overlay-и и возвращает окно без перезапуска.504 ui loop unresponsiveозначает, что заблокирован сам главный цикл Fyne, а это другая ошибка. Capabilityuiв манифесте.