Release v0.9.7
Downloads
macOS (Universal) - Supports both Apple Silicon and Intel
Option 1: Installation Script (Recommended)
Install with a single command (version v0.9.7):
curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v0.9.7The 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.9.7-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.9.7-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.9.7-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.
v0.9.7 — 2026-05-25
Quality-of-life release on top of v0.9.6: Traffic Profiler ships, a couple of nasty regressions (DNS user-server vanishing after reopen, Saved-states dropdown silently wiping unsaved work) are fixed, Rules tab gets clearer (🔗 preset badge, ⚠ for missing-but-enabled SRS + silent auto-download), and the debug API gains ~15 new endpoints across SPEC 053–059.
EN
Highlights
- Traffic Profiler — new diagnostics window opened from the Diagnostics tab. Shows live DNS / TCP / UDP events from sing-box with process attribution, per-process recording with Domains / IPs / Connections aggregations, and one-click verbose-log toggle for full DNS chain reconstruction. In-memory only — sessions wipe on app quit. See
docs/TRAFFIC_PROFILER.md. - DNS — your servers and rules no longer disappear after reopen. A user-added DNS server (e.g.
192.168.10.1for your home router) or a custom DNS rule entered in the wizard kept rendering in Preview but vanished from the form on the next configurator open — a regression from the DNS schema rework. Now properly restored from state on every reopen. Existing user DNS data is safe: it was always written to disk correctly; only the read path was broken. - Rules tab — preset rules clearly marked + SRS files auto-fetch. Preset-library rules now show a 🔗 prefix so it's obvious which rules come from the bundled library (
🔗 Russian domains & IPs) vs your own+ Add Ruleentries. And: if a preset is enabled but its rule-set file (.srs) isn't on disk yet — common after a state import or cache wipe — the launcher now shows a ⚠ badge and silently downloads the file in the background. No more "rule is enabled but doesn't work" mystery, no more failure popups on every configurator open. - Main screen — Saved-states dropdown no longer wipes your work. Picking a state from the dropdown used to silently overwrite the current state.json. One real-world casualty: clicking the wrong entry blew away unsaved preset edits with no warning. Now there's a 3-button prompt — Save current… / Discard / Cancel — that lets you stash the live state under a name before switching.
- Template updates now reach you automatically. Previously when a new launcher version shipped with an updated outbound (new comment, tweaked options, extra group), your existing config kept the stale copy. Now outbound entries in
state.jsonare thin references — body lives in the template — so template changes flow through to your config on the next launch without any manual reset. Your custom edits on top still persist as field-level diff. - «Restore missing» now revives outbounds correctly. Deleting
auto-proxy-outand bringing it back via Restore now properly inherits all active preset filters (e.g. the «no Russian proxies» patch from the Russian domains preset). Previously you had to toggle the preset off/on to re-apply the filter. - Edit outbound — URLTest fields are now editable. For automated (urltest) outbounds —
auto-proxy-outand similar — Edit dialog now exposes Interval / Tolerance / URL as dropdowns. Pick a preset value or select@urltest_url(etc.) to inherit the value you configured in Settings tab. wizard.*field removed. The legacywizard: {required: 1}wrapper in templates is replaced by a top-levelrequired: truefield. Existing templates withwizard.requiredcontinue to work via fallback, but new templates should use the top-level form.
Fixed
- Traffic Profiler button no longer hangs the app. Two-part deadlock in the singleton window manager (mutex held across sub-builds + synchronous
fyne.Dofrom UI thread); fixed by releasing the mutex before sub-builds and deferring the initial title refresh. - Dead
selectable_ruleslibrary code removed. The pre-SPEC-053 templateselectable_rules[]mechanism was already neutralized but ~500 lines of zombie machinery (loader fields, no-op migration, helpers, deprecated warnings) lingered behind it. Cleared out — old templates that still carry the field have it silently ignored byjson.Unmarshal. Net –393 lines.
Technical / Internal
- Debug API extended (SPEC 050 + 053 + 056 + 057 + 058 + 059). New endpoints under
/state/*and/traffic/*:GET /state/full— full marshalled state.GET/PATCH /state/rules— body{mode: "replace"|"append", rules: […]}.GET/PATCH /state/dns— replace wholedns_optionssection.GET/PATCH /state/dns/rules— wizard-text view of USER rules only ({text: "…"}), preset rules preserved.GET /state/outbounds/resolved— merged outbound bodies (afterMergeOutboundUpdatesInPlace+ ref resolve), for fixtures / external diff./traffic/status,/live,/sessions,/sessions/{id},/processes,/start,/stop,/clear,/verbose— 11 endpoints mirroring the Traffic Profiler UI for scripting and automation.- Verbose toggle returns 202 (sing-box restart is async); error codes follow SPEC 050: 400 bad JSON, 422 semantic, 409 conflict, 404 missing, 500 save failure.
core/log_level.goextracted fromui/traffic_verbose.goso the debug-API package can changevars.log_levelwithout pulling in Fyne.
- DNS restore path fixed. New
populateUserDNSFromStatehelper inui/configurator/presentation/preset_ref_helpers.goreadskind=userentries fromstate.DNS.{Servers,Rules}back intomodel.DNSServers/model.DNSRulesText. The legacyLoadPersistedWizardDNS(sf.DNSOptions)path is preserved for v5 round-trips; the new helper runs after it and skips tags already populated. 6 round-trip tests cover the helper. - SPEC 058 STATE_AS_TEMPLATE_DIFF. Outbound entries in
state.connections.outbounds[]split into two classes:- Direct (
refabsent) — self-contained body, full user ownership. - Referenced (
ref: "#TEMPLATE#"orref: "<preset_id>") — thin shape (onlytag+ref+updates), body resolved live fromtemplate.parser_config.outbounds[]ortemplate.presets[].outbounds[]at render/build time.
- Direct (
- USER edits on referenced entries become field-level
OutboundFieldDiffstored inupdates[]withref: "#USER#"— always last in the stack, replace-not-append on each Save. - One-shot migration on first load converts legacy SPEC 057 state (direct entries with snapshotted body) → referenced shape + USER patch with diff against
template + active preset patches(not raw template — preset edits stay correctly attributed). Backup:state.json.pre-058.bak, lossless rollback. - Sentinel constants
RefTemplate = "#TEMPLATE#",RefUser = "#USER#"incore/config/configtypes. State loader validates positional rules (entry-level vs updates-level). - New helpers:
core/build/migrate_outbounds_spec058.go,core/build/outbound_diff.go. Resolver expansion incore/build/resolve_outbounds.go(3-way classify: direct/template/preset). - UI: collectRows shows ✏ badge on referenced entries with USER patch. Reset button clears USER patch (not body replace). Edit dialog: form populated via
wizardbusiness.ResolveMergedOutbound(same pipeline as Preview/build emit). Settings ↔ JSON tab sync handles thin shape correctly. - SPEC 060 STATE_NAMESPACE_COLLAPSE.
core/state/v5/andcore/state/v6/subpackages collapsed into unifiedcore/state/.State.RulesV6→State.Rules(~50+ callsites updated). Dual write path (useV6gate,marshalDiskV6vsmarshalDisk) removed — Save always writes canonical v6 shape. Wire format on disk unchanged; v5 files still read correctly viaparseV5Legacy. Legacy DNS shape exposed asstate.LegacyDNSOptionsV5for UI back-compat.parseV6renamed toparseCurrent. ~26 import callsites incore/andui/updated. - SPEC 059 TRAFFIC_PROFILER. New
internal/trafficpackage: always-on background pipeline that joins Clash API/connectionspolling withsing-box.logtailing (fsnotify + rotation/truncate detection) and exposes a 60-second rolling buffer + active session API. Newinternal/platform/proclist_{darwin,windows,linux}.go— running-process enumeration for the process-picker dialog (best-effort per OS).bin/wizard_template.jsongainsroute.find_process: trueby default so process attribution works out of the box. UI lives inui/traffic/— singleton window opened from Diagnostics tab button. - Rules tab — runtime gate against missing SRS for enabled presets.
runSRSDownloadAsyncgains asilent boolparameter (suppresses failure popup); preset row render now kicks the silent download automatically when SRS missing on an enabled rule and shows a ⚠ badge. - Main screen — state-switch prompt.
ui/core_dashboard_tab.go::stateSelect.OnChangednow routes throughconfirmStateSwitch→promptSaveCurrentStateAsbefore overwritingstate.json. Save-as reuseswizardmodels.ValidateStateID. No new dependencies.
RU
Основное
- Профайлер трафика — новое окно диагностики, открывается с вкладки Diagnostics. Показывает live-поток DNS/TCP/UDP событий sing-box с привязкой к процессам, recording по конкретному процессу с агрегатами по доменам/IP/соединениям и one-click toggle verbose-логов для полной DNS chain reconstruction. In-memory only — сессии стираются при выходе из приложения. Смотри
docs/TRAFFIC_PROFILER.md. - DNS — твои серверы и правила больше не пропадают после reopen. User-added DNS server (например,
192.168.10.1для домашнего роутера) или custom DNS rule введённый в визарде продолжали рендериться в Preview, но исчезали из формы при следующем открытии configurator'а — регрессия после переработки DNS-схемы. Теперь корректно восстанавливаются из state на каждом reopen. Существующие user-DNS данные в безопасности: на диск всегда писались правильно, сломан был только read path. - Rules tab — preset-правила явно отмечены + SRS-файлы автоподтягиваются. Preset-library правила теперь с префиксом 🔗 — сразу видно какие правила из bundled library (
🔗 Russian domains & IPs) vs твои собственные через+ Add Rule. И: если preset enabled но его rule-set файл (.srs) ещё не на диске — типично после импорта state'а или wipe'а кэша — launcher теперь показывает ⚠ badge и тихо скачивает файл в фоне. Больше никакой загадки «правило включено но не работает», никаких failure popup'ов на каждом открытии configurator'а. - Главный экран — dropdown «Saved states» больше не стирает твою работу. Выбор state'а из dropdown'а раньше тихо перезаписывал текущий state.json. Реальный случай: клик не туда → unsaved preset-правки потеряны без предупреждения. Теперь — 3-кнопочный prompt: Save current… / Discard / Cancel — даёт сохранить текущий state под именем перед переключением.
- Обновления template приходят к тебе автоматически. Раньше при выходе новой версии launcher'а с обновлённым outbound'ом (новый комментарий, доработанные options, новая группа) твоя сохранённая конфигурация продолжала жить со старой копией. Теперь outbound entry в
state.json— это тонкая ссылка, body живёт в template'е, и template-обновления приходят к тебе на следующем запуске без manual reset. Твои собственные правки остаются как field-level diff. - «Restore missing» теперь правильно восстанавливает outbounds. Удалил
auto-proxy-out→ восстановил через Restore — теперь сразу подтягивает все активные preset-фильтры (например, фильтр «не использовать российские прокси» от Russian domains preset). Раньше приходилось выключать и обратно включать preset чтобы фильтр применился. - Edit outbound — поля URLTest стали редактируемыми. Для urltest-outbound'ов (
auto-proxy-outи похожие) в Edit диалоге появился блок «URLTest options» с тремя dropdown'ами: Interval / Tolerance / URL. Можно выбрать preset значение или@urltest_url(и т.п.) чтобы наследовать значение из Settings tab. - Поле
wizard.*убрано. Legacy обёрткаwizard: {required: 1}в template'ах заменена на top-levelrequired: true. Старые template'ы сwizard.requiredещё работают через fallback, но в новых — используем top-level форму.
Исправлено
- Кнопка Traffic Profiler больше не вешает приложение. Двухчастный deadlock в singleton window manager (mutex держался через все sub-builds + синхронный
fyne.Doс UI-thread); починили — отпускаем mutex перед sub-builds, defer'им первоначальный title refresh. - Удалён мёртвый код library
selectable_rules. Pre-SPEC-053 механизмselectable_rules[]в template'е был уже нейтрализован, но ~500 строк зомби-кода (поля loader'а, no-op миграция, helpers, deprecated warnings) висели за ним. Вычистили — старые template'ы с этим полем теперь silently ignored черезjson.Unmarshal. Net –393 строки.
Техническое / Внутреннее
- Debug API расширен (SPEC 050 + 053 + 056 + 057 + 058 + 059). Новые endpoints под
/state/*и/traffic/*:GET /state/full— полный marshalled state.GET/PATCH /state/rules— body{mode: "replace"|"append", rules: […]}.GET/PATCH /state/dns— replace всей секцииdns_options.GET/PATCH /state/dns/rules— wizard-text вид только USER-правил ({text: "…"}), preset-правила сохраняются.GET /state/outbounds/resolved— merged outbound bodies (послеMergeOutboundUpdatesInPlace+ ref resolve), для fixtures / внешнего diff./traffic/status,/live,/sessions,/sessions/{id},/processes,/start,/stop,/clear,/verbose— 11 endpoints, зеркалят UI Traffic Profiler для скриптинга/автоматизации.- Verbose toggle возвращает 202 (sing-box restart асинхронный); коды ошибок по SPEC 050: 400 bad JSON, 422 semantic, 409 conflict, 404 missing, 500 save failure.
core/log_level.goвынесен изui/traffic_verbose.go— debug-API теперь может менятьvars.log_levelбез зависимости от Fyne.
- DNS restore path починен. Новый helper
populateUserDNSFromStateвui/configurator/presentation/preset_ref_helpers.goчитаетkind=userentries изstate.DNS.{Servers,Rules}обратно вmodel.DNSServers/model.DNSRulesText. Legacy путьLoadPersistedWizardDNS(sf.DNSOptions)оставлен для v5 round-trip'ов; новый helper запускается после него и пропускает уже-populated теги. 6 round-trip тестов покрывают helper. - SPEC 058 STATE_AS_TEMPLATE_DIFF. Outbound entries в
state.connections.outbounds[]поделились на два класса:- Прямые (
refотсутствует) — self-contained body, полное юзерское владение. - Ссылочные (
ref: "#TEMPLATE#"илиref: "<preset_id>") — thin shape (толькоtag+ref+updates), body резолвится live изtemplate.parser_config.outbounds[]илиtemplate.presets[].outbounds[]на render/build time.
- Прямые (
- USER правки на ссылочные entries становятся field-level
OutboundFieldDiffвupdates[]сref: "#USER#"— всегда последний в стеке, replace-not-append при каждом Save. - Однопроходная migration на первом load конвертирует legacy SPEC 057 state (прямые entries с snapshot'нутым body) → ссылочный shape + USER patch с diff против
template + active preset patches(не raw template — preset правки корректно атрибутируются). Backup:state.json.pre-058.bak, lossless rollback. - Sentinel константы
RefTemplate = "#TEMPLATE#",RefUser = "#USER#"вcore/config/configtypes. State loader валидирует positional rules (entry-level vs updates-level). - Новые helpers:
core/build/migrate_outbounds_spec058.go,core/build/outbound_diff.go. Resolver расширен вcore/build/resolve_outbounds.go(3-way classify: direct/template/preset). - UI: collectRows показывает ✏ badge для ссылочных entries с USER patch'ем. Reset кнопка чистит USER patch (не replace body). Edit диалог: форма заполняется через
wizardbusiness.ResolveMergedOutbound(тот же pipeline что Preview/build emit). Settings ↔ JSON tab sync корректно обрабатывает thin shape. - SPEC 060 STATE_NAMESPACE_COLLAPSE. Подпакеты
core/state/v5/иcore/state/v6/свёрнуты в единыйcore/state/.State.RulesV6→State.Rules(~50+ callsite'ов). Dual write path (useV6gate,marshalDiskV6vsmarshalDisk) удалён — Save всегда пишет canonical v6 shape. Wire format на диске не меняется; v5 файлы по-прежнему читаются черезparseV5Legacy. Legacy DNS shape остался доступен какstate.LegacyDNSOptionsV5(для UI backward-compat).parseV6→parseCurrent. ~26 import-callsite'ов вcore/иui/обновлены. - SPEC 059 TRAFFIC_PROFILER. Новый пакет
internal/traffic: always-on background pipeline, объединяющий polling Clash API/connectionsс tailingsing-box.log(fsnotify + детект rotation/truncate); экспортит 60-секундный rolling-буфер и API активной сессии. Новыйinternal/platform/proclist_{darwin,windows,linux}.go— enumeration запущенных процессов для process-picker диалога (best-effort per OS).bin/wizard_template.jsonтеперь содержитroute.find_process: trueпо умолчанию — process attribution работает из коробки. UI живёт вui/traffic/— singleton окно открывается кнопкой с Diagnostics tab. - Rules tab — runtime защита от missing SRS у enabled preset'ов.
runSRSDownloadAsyncпринимаетsilent bool(подавляет failure popup); preset row render теперь автоматически запускает silent download при missing SRS у enabled rule + показывает ⚠ badge. - Главный экран — state-switch prompt.
ui/core_dashboard_tab.go::stateSelect.OnChangedтеперь идёт черезconfirmStateSwitch→promptSaveCurrentStateAsперед перезаписьюstate.json. Save-as переиспользуетwizardmodels.ValidateStateID. Новых зависимостей нет.