github Leadaxe/singbox-launcher v0.9.7
release v0.9.7

6 hours ago

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.7

The 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

  1. Download: singbox-launcher-v0.9.7-macos.zip
  2. Extract the ZIP file
  3. Remove quarantine attribute (required):
    xattr -cr "singbox-launcher.app" && chmod +x "singbox-launcher.app/Contents/MacOS/singbox-launcher"
  4. Double-click singbox-launcher.app to 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)

  1. Download: singbox-launcher-v0.9.7-win64.zip
  2. Extract the ZIP file to a folder, for example: C:\Program Files\singbox-launcher\
  3. Run singbox-launcher.exe from that folder
    • You may need administrator rights to install to Program Files
    • The launcher will automatically download sing-box and wintun.dll on first launch

Windows 7 (x86, legacy)

  1. Download: singbox-launcher-v0.9.7-win7-32.zip
  2. 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.1 for 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 Rule entries. 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.json are 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-out and 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-out and 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 legacy wizard: {required: 1} wrapper in templates is replaced by a top-level required: true field. Existing templates with wizard.required continue 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.Do from UI thread); fixed by releasing the mutex before sub-builds and deferring the initial title refresh.
  • Dead selectable_rules library code removed. The pre-SPEC-053 template selectable_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 by json.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 whole dns_options section.
    • GET/PATCH /state/dns/rules — wizard-text view of USER rules only ({text: "…"}), preset rules preserved.
    • GET /state/outbounds/resolved — merged outbound bodies (after MergeOutboundUpdatesInPlace + 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.go extracted from ui/traffic_verbose.go so the debug-API package can change vars.log_level without pulling in Fyne.
  • DNS restore path fixed. New populateUserDNSFromState helper in ui/configurator/presentation/preset_ref_helpers.go reads kind=user entries from state.DNS.{Servers,Rules} back into model.DNSServers / model.DNSRulesText. The legacy LoadPersistedWizardDNS(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 (ref absent) — self-contained body, full user ownership.
    • Referenced (ref: "#TEMPLATE#" or ref: "<preset_id>") — thin shape (only tag + ref + updates), body resolved live from template.parser_config.outbounds[] or template.presets[].outbounds[] at render/build time.
  • USER edits on referenced entries become field-level OutboundFieldDiff stored in updates[] with ref: "#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#" in core/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 in core/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/ and core/state/v6/ subpackages collapsed into unified core/state/. State.RulesV6State.Rules (~50+ callsites updated). Dual write path (useV6 gate, marshalDiskV6 vs marshalDisk) removed — Save always writes canonical v6 shape. Wire format on disk unchanged; v5 files still read correctly via parseV5Legacy. Legacy DNS shape exposed as state.LegacyDNSOptionsV5 for UI back-compat. parseV6 renamed to parseCurrent. ~26 import callsites in core/ and ui/ updated.
  • SPEC 059 TRAFFIC_PROFILER. New internal/traffic package: always-on background pipeline that joins Clash API /connections polling with sing-box.log tailing (fsnotify + rotation/truncate detection) and exposes a 60-second rolling buffer + active session API. New internal/platform/proclist_{darwin,windows,linux}.go — running-process enumeration for the process-picker dialog (best-effort per OS). bin/wizard_template.json gains route.find_process: true by default so process attribution works out of the box. UI lives in ui/traffic/ — singleton window opened from Diagnostics tab button.
  • Rules tab — runtime gate against missing SRS for enabled presets. runSRSDownloadAsync gains a silent bool parameter (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.OnChanged now routes through confirmStateSwitchpromptSaveCurrentStateAs before overwriting state.json. Save-as reuses wizardmodels.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-level required: 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=user entries из 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.RulesV6State.Rules (~50+ callsite'ов). Dual write path (useV6 gate, marshalDiskV6 vs marshalDisk) удалён — Save всегда пишет canonical v6 shape. Wire format на диске не меняется; v5 файлы по-прежнему читаются через parseV5Legacy. Legacy DNS shape остался доступен как state.LegacyDNSOptionsV5 (для UI backward-compat). parseV6parseCurrent. ~26 import-callsite'ов в core/ и ui/ обновлены.
  • SPEC 059 TRAFFIC_PROFILER. Новый пакет internal/traffic: always-on background pipeline, объединяющий polling Clash API /connections с tailing sing-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 теперь идёт через confirmStateSwitchpromptSaveCurrentStateAs перед перезаписью state.json. Save-as переиспользует wizardmodels.ValidateStateID. Новых зависимостей нет.

Don't miss a new singbox-launcher release

NewReleases is sending notifications on new releases.