fix(build): restore with_clash_api on desktop/CLI — drop is AAR-only

SPEC 014 dropped with_clash_api because LxBox (Android) drives the core
over the native libbox CommandClient, making the Clash REST server dead
weight in the AAR. But the drop landed in the shared Makefile.lx LX_TAGS,
which also feeds every desktop/CLI release build (mac/windows/linux-musl
via `make -s lx-print-tags`). A CLI binary has no CommandClient channel —
it is managed by external dashboards (yacd/MetaCubeXD) over the Clash REST
API — so every desktop release since rc.1 shipped with no way to manage
the core; a config with experimental.clash_api failed fast. CI stayed
green (lx-ci BASE_TAGS kept the tag), so it was invisible in CI.

Restore with_clash_api to the desktop LX_TAGS; leave build_libbox (AAR)
unchanged. The two tag sets now diverge by design: desktop = with Clash
API, AAR = without.

Verified: desktop binary builds with with_clash_api in Tags; `check`
accepts an experimental.clash_api config; the Clash REST server comes up
live (endpoints answer 401 security-middleware, not the stub's fail-fast).

Docs: Makefile.lx comment, SPEC 014 (§2/§3.1 scoped to AAR + new §3.4),
lx-release.yml tag comment + notes line, changelog rc.17.
This commit is contained in:
Leadaxe
2026-06-30 13:23:53 +03:00
parent 51b3bd07a8
commit c35ccd0ea7
4 changed files with 78 additions and 23 deletions
+6 -4
View File
@@ -16,9 +16,11 @@ on:
permissions:
contents: write
# Build tags are owned by Makefile.lx (single source of truth). The desktop build
# uses its LX_TAGS default; the Android AAR uses build_libbox's own tag set + the
# lx: features baked into it. `make -f Makefile.lx -s lx-print-tags` prints the set
# Build tags are owned by Makefile.lx (single source of truth). The desktop/CLI build
# uses its LX_TAGS default (which KEEPS with_clash_api — CLI binaries are driven by
# external dashboards over the Clash REST API); the Android AAR uses build_libbox's own
# tag set (which DROPS with_clash_api — LxBox uses the native CommandClient). The two
# sets diverge by design. `make -f Makefile.lx -s lx-print-tags` prints the desktop set
# for the release notes so nothing is duplicated here.
jobs:
@@ -346,7 +348,7 @@ jobs:
### Standing features
- **AmneziaWG 2.0** (\`with_awg\`) — \`wireguard\` endpoint with \`jc/jmin/jmax\`, \`s1\`–\`s4\`, \`h1\`–\`h4\`, \`i1\`–\`i5\`.
- **XHTTP** transport (\`with_xhttp\`) — Xray-compatible "splithttp", composes with Reality (use \`auto\`; \`stream-one\` has a known framing bug).
- **CommandClient extensions** (\`with_lx_command\`) — native libbox gRPC parity for the dropped Clash API: URLTestOutbound, GetRules, GetGroups/GetOutbounds, Connection.Detour, SubscribeDNSQueries.
- **CommandClient extensions** (\`with_lx_command\`) — native libbox gRPC parity for the Clash API dropped from the **Android AAR**: URLTestOutbound, GetRules, GetGroups/GetOutbounds, Connection.Detour, SubscribeDNSQueries. (Desktop/CLI binaries keep \`with_clash_api\` for external dashboards.)
### Binaries
Drop-in \`sing-box\` for **darwin / windows** × {amd64, arm64}, plus a **Windows 7 (32-bit)** legacy build (\`sing-box-${{ steps.ver.outputs.version }}-windows-386-legacy-windows-7.zip\` — built with a Win7-patched Go; without naive/cronet, which has no windows/386 target).
+19 -11
View File
@@ -2,17 +2,25 @@
# New file (zero edits to upstream Makefile) — see SPECS/CONSTITUTION.md §3.2.
# Usage: make -f Makefile.lx lx-build
# Canonical lx build-tag set — single source of truth (mirror changes in SPECS/004).
# = upstream feature set (release/DEFAULT_BUILD_TAGS) minus tags irrelevant to a VPN
# client — with_tailscale (no tailscale endpoints), with_ccm/with_ocm (Claude Code /
# OpenAI Codex proxy services), with_acme (server-side TLS cert issuance), with_clash_api
# (LxBox manages the core over the native libbox CommandClient, so the Clash REST API is
# dead weight; a config using experimental.clash_api fails fast, no silent fallback) —
# plus with_purego (CGO-free cross-compile covers with_naive_outbound via cronet
# prebuilts) and our two downstream features. with_purego/badlinkname need
# -checklinkname=0 in LX_LDFLAGS, otherwise the linker rejects badtls' go:linkname into
# crypto/tls. Mirror the Android AAR set in cmd/internal/build_libbox/main.go.
LX_TAGS ?= with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_xhttp,with_awg,with_lx_command
# Canonical lx build-tag set for the desktop/CLI binaries — single source of truth
# (mirror changes in SPECS/004). = upstream feature set (release/DEFAULT_BUILD_TAGS)
# minus tags irrelevant to a VPN client — with_tailscale (no tailscale endpoints),
# with_ccm/with_ocm (Claude Code / OpenAI Codex proxy services), with_acme (server-side
# TLS cert issuance) — plus with_purego (CGO-free cross-compile covers
# with_naive_outbound via cronet prebuilts) and our downstream features.
#
# with_clash_api IS kept here: the desktop/CLI binary is driven through the Clash REST
# API by external dashboards (yacd / MetaCubeXD / clash-dashboard); there is no native
# CommandClient channel outside the gomobile/libbox binding, so dropping it would leave
# a CLI user with no way to manage the core (a config using experimental.clash_api would
# fail fast). It is dropped ONLY from the Android AAR (cmd/internal/build_libbox/main.go),
# where LxBox manages the core over the native libbox CommandClient and the Clash server
# is dead weight. So the two tag sets diverge by design — do NOT blindly mirror the AAR
# set here.
#
# with_purego/badlinkname need -checklinkname=0 in LX_LDFLAGS, otherwise the linker
# rejects badtls' go:linkname into crypto/tls.
LX_TAGS ?= with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_clash_api,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_xhttp,with_awg,with_lx_command
# lx build counter over a given upstream base (override in CI/release: make -f Makefile.lx lx-build LX_BUILD=3).
LX_BUILD ?= 1
@@ -3,9 +3,9 @@
| Поле | Значение |
|------|----------|
| Тип | F (feature) — смена канала управления ядром (client-side) |
| Статус | A (accepted) — `with_clash_api` drop в `v1.14.0-lx.1-rc.1`; box.go-фикс в `v1.14.0-lx.1-rc.3` |
| Статус | A (accepted) — `with_clash_api` drop из AAR в `v1.14.0-lx.1-rc.1`; box.go-фикс в `rc.3`; десктоп-регрессия исправлена в `rc.17` (§3.4) |
**Переезд управления ядром с Clash API на нативный libbox CommandClient.** LxBox перестаёт использовать Clash REST API и переходит на нативный gRPC-канал `StartedService` (поверх unix-сокета). Из сборки убирается `with_clash_api` — отпадает HTTP-сервер Clash и связанный attack surface.
**Переезд управления ядром с Clash API на нативный libbox CommandClient — на Android.** LxBox перестаёт использовать Clash REST API и переходит на нативный gRPC-канал `StartedService` (поверх unix-сокета). Из **AAR-сборки** убирается `with_clash_api` — отпадает HTTP-сервер Clash и связанный attack surface. **Десктоп/CLI сохраняют `with_clash_api`** (внешние дашборды ходят по Clash REST API; нативного CommandClient-канала у CLI нет) — см. §3.4.
Этот SPEC фиксирует **сам переезд и его последствия**. Доработки command-протокола, понадобившиеся, чтобы CommandClient заменил Clash API по функциональности (per-node delay, таблица правил, pull-снапшоты групп, фикс потери групп), вынесены в отдельный **[SPEC 015 — COMMAND_PROTOCOL_RPC_EXTENSIONS](../015-COMMAND_PROTOCOL_RPC_EXTENSIONS/SPEC.md)**.
@@ -26,17 +26,19 @@ LxBox переходит на CommandClient как единственный ка
## 2. Цель
LxBox управляет ядром **только** через CommandClient; `with_clash_api` не входит в сборку. Конфиг, ссылающийся на `experimental.clash_api`, fail-fast с понятной ошибкой (а не молчаливо деградирует). Функциональный паритет с Clash API по нужным UI возможностям достигается доработками CommandClient — см. [SPEC 015](../015-COMMAND_PROTOCOL_RPC_EXTENSIONS/SPEC.md).
LxBox (Android) управляет ядром **только** через CommandClient; `with_clash_api` не входит в **AAR-сборку**. Конфиг, ссылающийся на `experimental.clash_api`, fail-fast с понятной ошибкой (а не молчаливо деградирует). Функциональный паритет с Clash API по нужным UI возможностям достигается доработками CommandClient — см. [SPEC 015](../015-COMMAND_PROTOCOL_RPC_EXTENSIONS/SPEC.md).
> **Важно (исправлено):** дроп `with_clash_api` относится **только к Android AAR**. Десктоп/CLI-бинари (mac/windows/linux) управляются внешними дашбордами (yacd/MetaCubeXD) **именно через Clash REST API** — нативного CommandClient-канала вне gomobile/libbox у них нет. Поэтому `with_clash_api` **остаётся** в десктоп `LX_TAGS`. Изначально (rc.1) тег был ошибочно убран и из десктоп-набора тоже — см. §3.4.
---
## 3. Требования
### 3.1 Дроп `with_clash_api`
- Убрать `with_clash_api` из `sharedTags` ([cmd/internal/build_libbox/main.go](../../cmd/internal/build_libbox/main.go), `// lx:`-блок) и из десктоп `LX_TAGS` (`Makefile.lx`).
- Без тега подключается `include/clashapi_stub.go` — конфиг с `experimental.clash_api` получает `clash api is not included in this build, rebuild with -tags with_clash_api` (fail-fast, **не** молчаливый отказ).
- lx-конфиги `clash_api` не используют — управление идёт через CommandClient.
- Сделано в `v1.14.0-lx.1-rc.1` (commit `57b5b5e5`).
### 3.1 Дроп `with_clash_api` — **только Android AAR**
- Убрать `with_clash_api` из `sharedTags` ([cmd/internal/build_libbox/main.go](../../cmd/internal/build_libbox/main.go), `// lx:`-блок). **Десктоп `LX_TAGS` (`Makefile.lx`) тег сохраняет** — см. §3.4.
- Без тега (в AAR) подключается `include/clashapi_stub.go` — конфиг с `experimental.clash_api` получает `clash api is not included in this build, rebuild with -tags with_clash_api` (fail-fast, **не** молчаливый отказ).
- lx-конфиги на Android `clash_api` не используют — управление идёт через CommandClient.
- Сделано в `v1.14.0-lx.1-rc.1` (commit `57b5b5e5`) — но изначально ошибочно срезано и с десктопа, исправлено в §3.4.
### 3.2 Доработки CommandClient → SPEC 015
Нативный CommandClient беднее Clash API по ряду возможностей, нужных UI (per-node delay-тест, таблица правил, pull-снапшоты групп/узлов, баг потери одно-узловых групп). Все эти доработки — **в [SPEC 015](../015-COMMAND_PROTOCOL_RPC_EXTENSIONS/SPEC.md)** (класс §3.6, build-tag `with_lx_command`). `URLTestOutbound` и `GetRules` уже зашиплены (rc.2); `GetGroups`/`GetOutbounds` + фикс `len<2` — target rc.4. Здесь они только упоминаются как часть полного перехода; тех-спека — в 015.
@@ -72,6 +74,27 @@ log factory + traffic/connection-tracker; **только** явный `experimen
> `completed`, #4093 + PR #4094 живут; удаление #4240 — отдельная история, не
> бан.)
### 3.4 Фикс — `with_clash_api` ошибочно срезан и с десктопа (rc.17)
§3.1 в rc.1 убрал `with_clash_api` из **обоих** наборов тегов: и из `sharedTags`
AAR, и из десктоп `LX_TAGS` (`Makefile.lx`). Для AAR это верно (LxBox ходит по
CommandClient). **Для десктопа — ошибка:** mac/windows/linux-бинарь запускается как
CLI и управляется внешними дашбордами (yacd, MetaCubeXD, clash-dashboard)
**исключительно через Clash REST API** — нативного CommandClient-канала вне
gomobile/libbox у CLI нет. Без `with_clash_api` десктоп-юзер остался **без способа
управлять ядром**: конфиг с `experimental.clash_api` падает fail-fast.
Все релизные desktop/linux-musl сборки берут теги из
`make -f Makefile.lx -s lx-print-tags` ([lx-release.yml](../../.github/workflows/lx-release.yml)),
поэтому баг ушёл во все desktop-артефакты rc.1…rc.16 молча (CI-проверка
`lx-ci.yml BASE_TAGS` clash_api держала, так что компиляция была зелёной — баг
не виден в CI, только в релизном артефакте).
**Фикс:** вернуть `with_clash_api` в десктоп `LX_TAGS` (`Makefile.lx`). AAR-набор
(`build_libbox`) **не трогаем** — там дроп остаётся в силе. Так два набора тегов
расходятся **по дизайну**: desktop = с Clash API, AAR = без. Десктоп-сборки снова
управляются через Clash REST API из коробки.
---
## 4. Критерии приёмки
+22
View File
@@ -10,6 +10,28 @@ tracks only the fork. Versions are tagged `vX.Y.Z-lx.N`; releases are built by
`lx-release.yml`. Tags carrying an `-rc.N` / `-alpha.N` / `-beta.N` suffix publish
as GitHub **pre-releases** and never become "Latest".
#### v1.14.0-lx.1-rc.17
**Pre-release.** Fixes a build-tag regression that shipped in every desktop/CLI release
since rc.1: `with_clash_api` was dropped from **all** platforms, not just the Android AAR
it was meant for. No data-path change; desktop binaries only.
* **Desktop/CLI binaries get the Clash API back.** SPEC 014 dropped `with_clash_api`
because LxBox (Android) manages the core over the native libbox `CommandClient` — so on
the **AAR** the Clash REST server is dead weight. But the drop landed in the shared
`Makefile.lx` `LX_TAGS`, which also feeds every desktop/CLI release build
(mac/windows/linux-musl, via `make -s lx-print-tags`). A CLI binary has **no native
CommandClient channel** — it is driven by external dashboards (yacd, MetaCubeXD,
clash-dashboard) over the Clash REST API — so dropping the tag left desktop users with
no way to manage the core: a config with `experimental.clash_api` failed fast. CI stayed
green the whole time (`lx-ci.yml` kept `with_clash_api` in its check tags), so the bug
was invisible outside the release artifact. **Fix:** `with_clash_api` is restored to the
desktop `LX_TAGS`; the AAR tag set (`build_libbox`) still drops it. The two sets now
diverge by design — desktop = with Clash API, AAR = without. Verified: the desktop
binary builds with `with_clash_api`, `check` accepts an `experimental.clash_api` config,
and the Clash REST server comes up live (all endpoints answer instead of the stub's
fail-fast).
#### v1.14.0-lx.1-rc.16
**Pre-release.** Full client-side support for the extended Xray/sing-box-extended **XHTTP**