prerelease v1.3.1-52-gb97f13e-prerelease
Pre-releaseRelease v1.3.1-52-gb97f13e-prerelease
Downloads
macOS (Universal) - Supports both Apple Silicon and Intel
Option 1: Installation Script (Recommended)
Install with a single command (version v1.3.1-52-gb97f13e-prerelease):
curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v1.3.1-52-gb97f13e-prereleaseThe 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.3.1-52-gb97f13e-prerelease-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.3.1-52-gb97f13e-prerelease-win64.zip - 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 launcher will automatically download
sing-boxandwintun.dllon first launch
Windows 7 (x86, legacy)
- Download:
singbox-launcher-v1.3.1-52-gb97f13e-prerelease-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
Checksums
See checksums.txt for SHA256 checksums of all files.
⚠️ Pre-release build offv1.3.1-52-gb97f13e-prerelease— for testing only, not for production. Use the latest stable release on the Releases page if you are not sure.
Upcoming release — черновик
Сюда складываем пункты, которые войдут в следующий релиз. Перед релизом переносим в X-Y-Z.md и очищаем этот файл.
Не добавлять сюда мелкие правки только UI (порядок виджетов, выравнивание, стиль кнопок без смены действия и т.п.). Писать новое поведение: данные, форматы, сохранение, заметные для пользователя возможности.
EN
Highlights
-
Every remote machine now has its own config. Until now a single profile was shared by all of them: one wizard state, one built config. Configuring a second machine silently overwrote the first, and Deploy sent whichever config happened to be written last — a router could receive a config built for a VPS. Each machine now owns a directory holding its wizard state, snapshots, built
config.json, rule sets and subscription bodies, so machines can't overwrite or delete each other's files. Existing setups migrate automatically when exactly one machine is paired; with several paired the old files are left untouched and a warning is logged, because there is no way to tell whose they were. -
Machine management moved into one place: the new Local and Remote tabs. They replace Core and Servers and share one layout — proxy list on the left, management on the right. Local pairs the proxy list with your own core's controls; Remote pairs it with the list of machines, each row showing name, platform, address and core status, with Configure / Start-Stop / Deploy / edit / remove right there. Previously this was scattered across three screens (the Servers header, the connection window, the wizard), and none of them showed a machine as a whole.
-
Picking a machine and choosing what to build for are no longer separate switches. Configure on a machine's row opens the wizard rooted on that machine's profile, and Deploy on the same row sends that machine's own config — so "built for one, deployed to another" is impossible by construction rather than by validation. A machine's platform and architecture now belong to its registry entry (edit them in its row), which is also what the config is built for.
-
The main window now opens at 1000×700 and won't shrink below it. Both tabs are two-column, and below that size the columns stop fitting and labels get cut off. It can still be stretched.
-
Daemon mode for the core (macOS). The launcher can now run the VPN core inside a long-lived system service (
sing-box lxd) instead of spawningsing-box runitself — the same in-process, reload-surviving model the Android app uses. Configure it in the new connection settings window: Servers → ⚙ → Local (the Remote tab keeps the SPEC 064 remote Clash override). What it buys you:- Sudo once, in your own Terminal. Installing the service is a single command the launcher prepares for you (copy or open in Terminal — full launchctl output, your own sudo; the launcher itself never runs anything privileged). After that, starting/stopping the VPN and applying config changes need no password at all.
- Quitting the launcher can keep the VPN up. By default, closing the launcher leaves the core running in the daemon; a "Stop VPN when quitting" toggle restores the classic behavior.
- In-process config swaps. Applying a new config no longer kills and restarts a process: the daemon swaps the core in-place, validates the config in a subprocess before touching the running instance, and auto-rolls-back to the last working config if the new one fails to start.
- Richer observability over gRPC. Proxy groups, node selection, latency tests, live status/traffic, connections, and core logs all flow over the daemon's gRPC channel (the CommandClient protocol shared with the Android line) — including a new balancer pool view on the Servers tab showing each urltest slot and its delay.
- Pairing. The launcher pairs with the daemon over mTLS using a one-time invite (
address#fingerprint#code). The install command prints one at the end — paste it into the pairing field; mint a fresh one any time withsudo sing-box lxd client add(works for remote daemons too). The daemon fully owns its home directory and credentials (daemon.jsonwith the listen address and admin secret lives in its state dir, reported overGET /admin/info); the launcher keeps only its own client keypair — a trusted client certificate is the whole credential.
The classic engine remains the default and is unchanged; daemon mode is opt-in and requires a core build with the
lxdsubcommand (sing-box-lx 1.14.0-lx.23 or newer).
Fixed
- Quit from the tray actually terminates the process. Quitting via the tray menu (or the Exit button) with the main window hidden or unfocused left the process alive: on Windows the tray icon stayed behind as a ghost, and relaunching the
.exereported "already running" because the dead-looking process still held the single-instance lock. Root cause is in Fyne's glfw driver:Quit()runs its tray teardown only when one of our windows currently holds focus — exactly the opposite of the quit-from-tray situation. The launcher now tears the tray icon down explicitly (systray.Quit(), the same call the driver skips: on Windows it deletes the notification-area icon immediately and stops the systray message pump), and a shutdown watchdog force-exits the process within 3 seconds if the Fyne event loop still refuses to unwind — by that point sing-box is already stopped and log files are closed, so nothing is lost.
Technical / Internal
GracefulExitis now idempotent (sync.Once): it is reachable both from the tray/Exit button and frommain()afterapp.Run()returns, and used to run the whole teardown twice.fyne.io/systraypromoted from indirect to direct dependency ingo.win7.mod(v1.12.0, version unchanged);go.modalready had it direct (v1.12.2).- Core engine abstraction (
CoreBackend). The UI, tray, shortcuts, and debug-API no longer call the process manager or Clash API directly; everything routes through the active backend (LegacyBackend= classic spawn,DaemonBackend= lxd). Proxy-group operations go through aProxyTransportseam (Clash HTTP for classic, gRPC for daemon), so the Servers tab is engine-agnostic. Daemon mode addsgoogle.golang.org/grpc+protobuf(darwin-only build tags — the win7 build is untouched); the daemon protobuf stubs are vendored from the fork viascripts/sync_daemonpb.sh. - Daemon mode requires a core built with
with_lx_command(thelxdsubcommand).RequiredCoreVersionmust be bumped to a fork release that ships it (1.14.0-lx.23+) before the feature is usable by end users; until then it is developed against a locally built core. - Cleanup pass over the SPEC 094–099 code. Dead code removed (
pickMainXrayVLESS,xrayBuildJumpFromOutbound,containsStringValue,activateDaemonEngineIfPossible— all orphaned by their own refactors). Copy-to-clipboard unified: oneNewCopyButtonreplaces three drifting copies of the "icon turns into a checkmark" feedback, andfynewidget.SetClipboardreplaces the deprecated per-windowWindow.Clipboard()across both UI packages. Deploy's resource collection moved out of the machine-list panel intoservices.CollectDeployResources(no widgets in it — it now has unit tests, which the GUI-excludeduipackage could not have).ProcessBaseis shared instead of duplicated in the machine profiler. ui/componentsno longer drags incore.ClickRedirect— the only widget there that needed app state — took the whole*core.AppControllerjust to focus the wizard window, and through the shared widget package that dependency reached every file importing the gutter helpers from it (20+, acrossui,ui/configurator/*andui/traffic). It now takes*uiservice.UIService, a leaf package.ui/traffic, documented as isolated fromAppController, went from 20 transitive internal dependencies (core,core/services,core/build,core/config/subscription) down to 8 — the isolation its package doc claims is now real rather than aspirational.- Fixed while cleaning:
lxdOverrideTransportForIDtook the override lock twice (check id, then fetch transport), so a machine switch between the two reads could hand back the wrong machine's transport — now one snapshot under a single lock.CommandRow's copy button no longer flashes the success checkmark when the command failed to build.
RU
Основное
-
У каждой удалённой машины теперь свой конфиг. До этого профиль был один на всех: одно состояние визарда, один собранный конфиг. Настройка второй машины молча затирала первую, а Deploy отправлял то, что оказалось записано последним, — роутер мог получить конфиг, собранный для VPS. Теперь у каждой машины своя директория: её состояние визарда, снапшоты, собранный
config.json, rule-set'ы и тела подписок. Машины не могут перезаписать или удалить файлы друг друга. Существующие настройки переезжают автоматически, если сопряжена ровно одна машина; если их несколько — старые файлы остаются нетронутыми с предупреждением в логе, потому что определить владельца невозможно. -
Управление машинами собрано в одном месте — вкладки Local и Remote. Они заменяют Core и Servers и устроены одинаково: слева список прокси, справа управление. На Local список соседствует с управлением своим ядром, на Remote — со списком машин: в строке видно имя, платформу, адрес и состояние ядра, там же кнопки «Настроить», Start/Stop, Deploy, правка и удаление. Раньше это было размазано по трём экранам (шапка Servers, окно подключения, визард), и ни на одном не было видно машину целиком.
-
Выбор машины и выбор «для кого собираем» перестали быть разными переключателями. Кнопка «Настроить» в строке машины открывает визард, корневой на её профиле, а Deploy в той же строке отправляет её собственный конфиг — промах «собрал для одной, задеплоил на другую» стал невозможен по конструкции, а не по проверке. Платформа и архитектура машины теперь принадлежат её записи (правятся в той же строке) — под них и собирается конфиг.
-
Главное окно открывается в 1000×700 и не сжимается меньше. Обе вкладки двухколоночные, и ниже этого размера колонки перестают помещаться, а подписи обрезаются. Растягивать по-прежнему можно.
-
Daemon-режим ядра (macOS). Лаунчер теперь умеет запускать ядро VPN внутри долгоживущей системной службы (
sing-box lxd), а не спавнитьsing-box runсам — та же модель «ядро внутри процесса, канал управления переживает перезагрузку конфига», что и в Android-приложении. Настраивается в новом окне подключения: Servers → ⚙ → Local (вкладка Remote — прежний удалённый Clash-override SPEC 064). Что это даёт:- Sudo один раз, в вашем терминале. Установка службы — одна команда, которую лаунчер готовит за вас (скопировать или открыть в терминале — полный вывод launchctl, ваш собственный sudo; сам лаунчер ничего привилегированного не запускает). Дальше запуск/остановка VPN и смена конфига идут вообще без пароля.
- Выход из лаунчера может оставлять VPN работать. По умолчанию закрытие лаунчера не выключает ядро в демоне; галочка «Останавливать VPN при выходе» возвращает классическое поведение.
- Смена конфига без убийства процесса. Применение нового конфига больше не перезапускает процесс: демон подменяет ядро на месте, валидирует конфиг сабпроцессом до того, как тронуть работающий инстанс, и автоматически откатывается на последний рабочий конфиг, если новый не стартовал.
- Богатая наблюдаемость по gRPC. Группы прокси, выбор узла, тесты задержки, живой статус/трафик, соединения и логи ядра — всё идёт по gRPC-каналу демона (протокол CommandClient, общий с Android-линией), включая новый экран пула балансировщика на вкладке Servers: каждый слот urltest-группы и его задержка.
- Сопряжение. Лаунчер сопрягается с демоном по mTLS через одноразовое приглашение (
адрес#отпечаток#код). Команда установки печатает его в конце — вставьте в поле сопряжения; свежее можно выпустить в любой момент командойsudo sing-box lxd client add(работает и для удалённых демонов). Демон полностью владеет своим каталогом и учётными данными (daemon.jsonс адресом и админ-секретом живёт в его state-каталоге и виден черезGET /admin/info); у лаунчера остаётся только собственная клиентская пара — доверенный сертификат и есть весь мандат.
Классический движок остаётся по умолчанию и не меняется; daemon-режим включается вручную и требует сборки ядра с сабкомандой
lxd(sing-box-lx 1.14.0-lx.23 или новее).
Исправлено
- Quit из трея действительно завершает процесс. Выход через меню трея (или кнопку Exit) при скрытом или расфокусированном главном окне оставлял процесс живым: на Windows иконка в трее висела «призраком», а повторный запуск
.exeотвечал «процесс уже запущен» — внешне закрытое приложение продолжало держать single-instance lock. Корень — в glfw-драйвере Fyne:Quit()выполняет снятие трея только когда одно из окон приложения в фокусе, то есть ровно наоборот к ситуации «выход из трея». Теперь лаунчер снимает иконку явно (systray.Quit()— тот самый вызов, который драйвер пропускает: на Windows он немедленно удаляет иконку из области уведомлений и останавливает message pump систрея), а сторожевой таймер завершает процесс принудительно в пределах 3 секунд, если event loop Fyne так и не размотался — к этому моменту sing-box уже остановлен и лог-файлы закрыты, потерь нет.
Техническое / Внутреннее
GracefulExitтеперь идемпотентен (sync.Once): он достижим и из трея/кнопки Exit, и изmain()после возвратаapp.Run(), и раньше прогонял весь teardown дважды.fyne.io/systrayпереведён из indirect в прямую зависимость вgo.win7.mod(v1.12.0, версия не менялась); вgo.modон уже был прямым (v1.12.2).- Абстракция движка ядра (
CoreBackend). UI, трей, горячие клавиши и debug-API больше не зовут процесс-менеджер или Clash API напрямую — всё идёт через активный движок (LegacyBackend= классический spawn,DaemonBackend= lxd). Операции с группами прокси проходят через шовProxyTransport(Clash HTTP для classic, gRPC для daemon), поэтому вкладка Servers не зависит от движка. Daemon-режим добавляетgoogle.golang.org/grpc+protobuf(build-tag только darwin — win7-сборка не затронута); protobuf-стабы демона вендорятся из форка черезscripts/sync_daemonpb.sh. - Daemon-режим требует ядра, собранного с
with_lx_command(сабкомандаlxd). Перед тем как фича станет доступна конечным пользователям,RequiredCoreVersionнужно поднять до релиза форка с этим тегом (1.14.0-lx.23+); до этого разработка идёт против локально собранного ядра. - Чистка кода SPEC 094–099. Удалён мёртвый код (
pickMainXrayVLESS,xrayBuildJumpFromOutbound,containsStringValue,activateDaemonEngineIfPossible— все осиротели при собственных рефакторингах). Копирование в буфер сведено воедино: одинNewCopyButtonвместо трёх разъезжавшихся копий фидбека «иконка на секунду становится галочкой», аfynewidget.SetClipboardзаменил устаревший пооконныйWindow.Clipboard()в обоих UI-пакетах. Сбор ресурсов для Deploy вынесен из панели списка машин вservices.CollectDeployResources(виджетов в нём нет — и на него появились юнит-тесты, невозможные в GUI-пакетеui, исключённом изgo test).ProcessBaseпереиспользуется вместо копии в профайлере машины. ui/componentsбольше не тянетcore.ClickRedirect— единственный виджет там, которому нужно состояние приложения, — принимал целый*core.AppControllerради того, чтобы сфокусировать окно визарда, и через общий пакет виджетов эта зависимость доставалась каждому файлу, который импортирует оттуда gutter-хелперы (20+, вui,ui/configurator/*иui/traffic). Теперь он принимает*uiservice.UIService— листовой пакет. Уui/traffic, задокументированного как изолированный отAppController, транзитивных внутренних зависимостей стало 8 вместо 20 (ушлиcore,core/services,core/build,core/config/subscription): изоляция, заявленная в доккомменте пакета, стала фактической, а не декларативной.- Попутно исправлено:
lxdOverrideTransportForIDбрал блокировку override дважды (сначала проверка id, потом получение транспорта) — смена машины между двумя чтениями могла вернуть транспорт не той машины; теперь один снимок под одной блокировкой. Кнопка копирования вCommandRowбольше не показывает галочку успеха, когда команду собрать не удалось.