Release v0.8.8
Downloads
macOS (Universal) - Supports both Apple Silicon and Intel
Option 1: Installation Script (Recommended)
Install with a single command (version v0.8.8):
curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v0.8.8The 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-v0.8.8-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-v0.8.8-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-v0.8.8-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.
What's New from 0.8.7
Version 0.8.8 Release Notes
EN
Highlights
-
NaïveProxy (
naive+https:///naive+quic://) support in the subscription parser and share-URI encoder. Parses user/pass,extra-headers, and QUIC vs HTTP/2 transport per the de-facto DuckSoft URI spec; emits a sing-box"type": "naive"outbound with the TLS block limited toserver_name(matching sing-box naive capabilities).padding=URI param is logged and ignored (no sing-box equivalent). Right-click → Copy link on a naive node round-trips back to a valid URI (extra-headerskeys sorted lexicographically for determinism). Requires sing-box ≥ 1.13.0 built withwith_naive_proxy— stock binaries without the build tag will reject the outbound. See SPEC 044 anddocs/ParserConfig.md→ NaïveProxy. -
macOS wake-from-sleep re-sync — closes the macOS half of SPEC 011 (Windows + Linux landed in 0.8.7). New
internal/platform/power_darwin.goregisters with IOKit viaIORegisterForSystemPower; the CFRunLoop runs on aruntime.LockOSThread-pinned goroutine. After resume the launcher resets the Clash API HTTP transport, refreshes the proxies list, and re-pings nodes if auto-ping is on — exactly the same flow as Windows / Linux. Sleep transitions are auto-acknowledged viaIOAllowPowerChangeso the system isn't held in a 30-second timeout waiting for a reply.
Added — Resilience & observability
- Per-source counts in the Update toast. When at least one subscription source returned an error or silently produced zero nodes, the success toast now reads
Config updated: 2/3 source(s) succeeded (1 failed)instead of a blanket "successfully". Silent-empty is treated as failure — from the user's perspective an empty subscription is indistinguishable from a network error. All-sources-OK case still shows the original toast text. Counters live onOutboundGenerationResult(already present in 0.8.7 but not surfaced). - Tooltips on Core Dashboard reveal keyboard shortcuts. Hover over Update or the round-arrow Restart button to see "Update subscriptions (⌘+U)" / "Restart sing-box (⌘+R)" — Ctrl on Windows / Linux. New helper
platform.ShortcutModifierLabel()resolves the platform-specific symbol; both buttons switched tottwidget.Buttonfor hover support. Shortcuts themselves were added in 0.8.7 (SPEC 042) — this just makes them discoverable.
Fixed
- Wizard template — object-form
options: [{title, value}]no longer corrupts substituted values. Previously,type: "text"+ object-form options rendered as a free-text combo widget (SelectEntry). The display shows the title (e.g. "5m (default)"), but the title→value mapping only fires when the user picks from the dropdown — typing or even selecting could leave the literal title in the entry, which then went straight intoconfig.json. Concretely: picking "5m (default)" forurltest_intervalended up writing"interval": "5m (default)"instead of"5m", and sing-box rejected the config. Fix: at JSON-unmarshal time (TemplateVar.UnmarshalJSON), anyoptionselement in object form forcesType = "enum"regardless of the declared type. Strict dropdowns can't be typed into. Legacy plain-string options (["a","b"]) are unaffected — combo with free typing still works for them. Six new unit tests cover the matrix.
Changed — Template defaults
- URLTest vars in
bin/wizard_template.jsonrewired to match the new rule:urltest_urlkeepstype: "text", butoptionsare now plain-string URLs (no titles). User sees a combo with presets and can still type a custom test endpoint.urltest_intervalandurltest_toleranceare now explicitlytype: "enum"— values stay object-form{title, value}(so the dropdown shows "5m (default)" / "100 ms (twitchy)" labels), but the widget is a strict dropdown. No more accidental typing of garbage.
Technical / Internal
- CI: per-version release-notes file required. The release job no longer concatenates
RELEASE_NOTES.md(the repo-level index) into the GitHub Release body — that was leaking sections from older versions and the upcoming-release draft into every release. CI now readsdocs/release_notes/<slug>.md(e.g.0-8-8.mdforv0.8.8). If the file is missing, the workflow fails before creating the release with a clear error pointing at the expected path. For prereleases the slug is computed fromgit describe. Prereleases also get an automatic> ⚠️ Pre-release buildbanner on top of the body. - New runbook
docs/RELEASE_PROCESS.md. Canonical procedure for stable and prerelease cuts: pre-flight, develop→main merge, separate tag push, post-tag main→develop merge-back (so the tag stays in develop's ancestry), troubleshooting, copy-paste checklists. Linked fromAGENTS.md§4 / §5 / §6. FallbackVersionbumped 1.13.6 → 1.13.11 incore/core_version.go— fallback used when GitHub API is unreachable / rate-limited.- SPEC groundwork for v0.9.x — two planning artifacts landed without code changes:
- SPEC 045 — State / Config Decoupling. Split Wizard Save (writes
state.jsononly) from Build Config (writesconfig.jsonfrom state + outbounds cache), modelled after the LxBox mobile client. IncludesLXBOX_NOTES.md(deep-dive of the mobile architecture) andCURRENT_ARCH_NOTES.md(audit of everyconfig.jsonwrite-point in the desktop launcher today). - SPEC 046 — Pinned Core and Template. Pin a specific sing-box version and a specific
wizard_template.jsoncommit per launcher version, so a launcher release doesn't silently float onto an untested sing-box.
- SPEC 045 — State / Config Decoupling. Split Wizard Save (writes
OutboundGenerationResultcounters now populated —TotalSources / SucceededSources / FailedSourcesare filled byGenerateOutboundsFromParserConfig.UpdateConfigFromSubscriptionsnow returns(*OutboundGenerationResult, error)instead of justerrorso callers can craft truthful messages.
Migration notes
- Custom
wizard_template.jsonfiles usingtype: "text"+ object-formoptions: [{title, value}]are silently normalized totype: "enum"at load time. Functionally a strict dropdown. If you actually want a free-text combo with presets, switch the options to plain strings (["a", "b"]). - The shipped
bin/wizard_template.jsonURLTest section was rewired (see above). If you maintain a custom template, the change is purely cosmetic on the launcher side — sing-box still receives the same@urltest_url / @urltest_interval / @urltest_tolerancesubstitutions.
Known issues / deferred for redesign
These items are not in 0.8.8 and are tracked for v0.9+:
- State / Config decoupling (SPEC 045) — the dirty marker on Update is still semantically smeared (fires on any wizard save, not just source-list edits). The next major release will split state-save from config-build and surface two independent markers (Update
*for source-set changes vs. a separate Restart marker for template changes). - Auto-update event-driven model — the polling loop in
core/auto_update.gois still the old "wake every minute, check timestamp, maybe run" pattern. Documented redesign: typed triggers (onAppStart,onVpnConnected,onPeriodic,onWakeFromSleep) through a single dispatcher, no background goroutine between events. - Right-click context menu on the Update button —
SecondaryTapWrapdoes not route secondary taps intowidget.Button; needs a customRightClickableButtonthat implementsfyne.SecondaryTappabledirectly. - Last-auto-update failure pill on Core Dashboard — wired but not visible in practice; layout / flag-path diagnosis pending.
- Ping-all button cancel — current design fully disables the button during a run; a click-to-cancel redesign (label swap to "Cancel" / "Cancelling…",
pingAllCancelledatomic) is tracked. - Pinned core + template per launcher version (SPEC 046) — currently the launcher fetches the latest sing-box and the HEAD of
bin/wizard_template.jsonfrom a branch. Pinning eliminates floating drift between launcher releases and untested core versions.
RU
Основное
-
Поддержка NaïveProxy (
naive+https:///naive+quic://) в парсере подписок и share-URI энкодере. Парсятся user/pass,extra-headers, выбор транспорта (HTTP/2 vs QUIC) по де-факто спеке DuckSoft; собирается sing-box outbound"type": "naive"с TLS-блоком толькоserver_name(ровно то, что умеет sing-box naive). Параметрpadding=логируется и игнорируется (нет соответствия в sing-box). ПКМ → «Copy link» на naive-ноде корректно round-trip-ит обратно в валидный URI (ключиextra-headersсортируются лексикографически — детерминированный round-trip). Требует sing-box ≥ 1.13.0 со сборкойwith_naive_proxy— стоковые бинарники без тега отклонят outbound. См. SPEC 044 иdocs/ParserConfig.md→ NaïveProxy. -
macOS wake-from-sleep re-sync — закрытие macOS-половины SPEC 011 (Windows + Linux появились в 0.8.7). Новый
internal/platform/power_darwin.goрегистрируется в IOKit черезIORegisterForSystemPower; CFRunLoop крутится на goroutine сruntime.LockOSThread. После резюма лаунчер сбрасывает HTTP-транспорт Clash API, перечитывает список прокси и re-пингует ноды, если включён автопинг — то же поведение, что на Windows / Linux. Sleep-транзишены авто-подтверждаются черезIOAllowPowerChange, чтобы система не залипала на 30-секундном таймауте ожидания ответа.
Устойчивость и наблюдаемость
- Счётчик источников в тосте Update. Если хотя бы один источник вернул ошибку или молча отдал ноль нод, тост успеха пишет
Config updated: 2/3 source(s) succeeded (1 failed)вместо общего «successfully». «Молчаливый ноль» считается failure — для пользователя это неотличимо от сетевой ошибки. Полный успех — оставлен старый текст. Счётчики живут вOutboundGenerationResult(присутствовали ещё в 0.8.7, но не отображались). - Tooltips на Core Dashboard показывают горячие клавиши. При наведении на Update и круговую стрелку Restart показываются «Обновить подписки (⌘+U)» / «Перезапустить sing-box (⌘+R)» (Ctrl на Windows / Linux). Helper
platform.ShortcutModifierLabel()отдаёт платформенный символ; обе кнопки переведены наttwidget.Buttonдля поддержки hover-а. Сами шорткаты появились в 0.8.7 (SPEC 042) — теперь они discoverable.
Исправлено
- Шаблон визарда — object-форма
options: [{title, value}]больше не портит подставляемые значения. Раньшеtype: "text"+ object-form options рендерился как combo-виджет (SelectEntry) со свободным вводом. Видимый текст — это title (например, «5m (default)»), а маппинг title→value срабатывал только при выборе из дропдауна; ручной ввод или даже клик мог оставить буквальный title в entry, и эта строка уезжала прямо вconfig.json. Конкретно: выбор «5m (default)» дляurltest_intervalприводил к"interval": "5m (default)"вместо"5m", и sing-box ругался на конфиг. Фикс: на этапе JSON-unmarshal-а (TemplateVar.UnmarshalJSON) любая object-форма вoptionsпринудительно выставляетType = "enum", независимо от заявленного типа. Строгий дропдаун невозможно ввести вручную. Legacy plain-string options (["a","b"]) не затронуты — combo со свободным вводом для них продолжает работать. Шесть новых юнит-тестов покрывают всю матрицу.
Шаблон по умолчанию
- URLTest-vars в
bin/wizard_template.jsonпереразведены под новое правило:urltest_urlосталсяtype: "text", ноoptionsтеперь plain-string URL-ы (без подписей). Юзер видит combo с пресетами, но всё ещё может вписать свой test-endpoint.urltest_intervalиurltest_toleranceтеперь явноtype: "enum"— значения остаются в object-форме{title, value}(чтобы дропдаун показывал «5m (default)» / «100 ms (twitchy)»), но виджет — строгий дропдаун. Случайно вписать мусор больше нельзя.
Техническое / Внутреннее
- CI: per-version release-notes файл обязателен. Release-job больше не конкатенирует
RELEASE_NOTES.md(репо-уровневый index) в тело GitHub Release — это протекало в каждый релиз секции старых версий и черновика следующего. CI теперь читаетdocs/release_notes/<slug>.md(например0-8-8.mdдляv0.8.8). Если файла нет — workflow падает до создания релиза с явной ошибкой, указывающей на ожидаемый путь. Для пререлизов slug вычисляется изgit describe. Пререлизы автоматически получают баннер> ⚠️ Pre-release buildповерх тела. - Новый runbook
docs/RELEASE_PROCESS.md. Canonical-процедура для stable и prerelease: pre-flight, мердж develop→main, отдельный пуш тега, обязательный возврат main→develop (чтобы тег остался в истории develop), траблшутинг, чеклисты для копипасты. Ссылки вAGENTS.md§4 / §5 / §6. FallbackVersion1.13.6 → 1.13.11 вcore/core_version.go— fallback используется, когда GitHub API недоступен / rate-limit.- Спеки-задел на v0.9.x — два планировочных артефакта без правок кода:
- SPEC 045 — State / Config Decoupling. Развести Wizard Save (пишет только
state.json) и Build Config (собираетconfig.jsonиз state + кэш outbounds), по образцу мобильного клиента LxBox. В папке:LXBOX_NOTES.md(deep-dive архитектуры мобилки) иCURRENT_ARCH_NOTES.md(карта всех write-point-овconfig.jsonв десктопе). - SPEC 046 — Pinned Core and Template. Жёстко закрепить версию sing-box и коммит
wizard_template.jsonза каждой версией лаунчера, чтобы релиз не уплывал на непротестированную версию ядра.
- SPEC 045 — State / Config Decoupling. Развести Wizard Save (пишет только
- Счётчики
OutboundGenerationResultтеперь заполняются —TotalSources / SucceededSources / FailedSourcesпишутся вGenerateOutboundsFromParserConfig.UpdateConfigFromSubscriptionsвозвращает(*OutboundGenerationResult, error)вместо простоerror, чтобы caller мог собрать честное сообщение пользователю.
Миграция
- Кастомные
wizard_template.jsonсtype: "text"+ object-formoptions: [{title, value}]тихо нормализуются вtype: "enum"при загрузке. Функционально — строгий дропдаун. Если хочется combo со свободным вводом и пресетами — переключите options в plain-string форму (["a", "b"]). - Поставляемый
bin/wizard_template.jsonURLTest-секция переразведена (см. выше). Если вы держите кастомный шаблон — изменение чисто косметическое на стороне лаунчера; sing-box всё равно получает те же подстановки@urltest_url / @urltest_interval / @urltest_tolerance.
Known issues / отложено на редизайн
Не входит в 0.8.8, отслеживается для v0.9+:
- State / Config decoupling (SPEC 045) — dirty-маркер
*на Update всё ещё семантически размазан (срабатывает на любое сохранение визарда, а не только на правки списка источников). Следующий major-релиз разнесёт сохранение state и сборку config и выведет два независимых маркера (Update*для изменения source-set vs. отдельный маркер на Restart для правок шаблона). - Event-driven автообновление подписок — polling loop в
core/auto_update.goостаётся старого образца («просыпайся каждую минуту, проверь timestamp, может пора»). Запланированный редизайн: типизированные триггеры (onAppStart,onVpnConnected,onPeriodic,onWakeFromSleep) через единый dispatcher, без background-goroutine между событиями. - Правый клик по кнопке Update —
SecondaryTapWrapне маршрутизирует secondary-тапы вwidget.Button; нужен кастомныйRightClickableButtonс прямой реализациейfyne.SecondaryTappable. - Плитка «Last auto-update failed» на Core Dashboard — реализована, но в практике не показывается; диагностика layout / wiring отложена.
- Кнопка Ping-all → Cancel — сейчас во время теста кнопка полностью disable; редизайн на click-to-cancel (лейбл «Cancel» / «Cancelling…», атомарный
pingAllCancelled) запланирован. - Pinned core + template (SPEC 046) — сейчас лаунчер тащит latest sing-box и HEAD ветки
bin/wizard_template.json. Жёсткое закрепление избавит от плавающего drift между релизами лаунчера и непротестированными версиями ядра.