You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Finish v4 cleanup and remove obsolete compatibility paths
Remove superseded pre-v4 state and rendering layers, preserve current v4 recovery semantics, and align generated contracts and guidance around one coherent architecture.
Co-authored-by: Cursor <cursoragent@cursor.com>
return sorted(set(item['url'] for item in json.load(open(p)) if re.match(r'https://(?:play\.google\.com|apps\.apple\.com|github\.com/)', item['url'])))
51
-
t = extract_template('src/meridian/templates/connection-info.html.j2')
Copy file name to clipboardExpand all lines: .github/workflows/CLAUDE.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
**Two-stage pipeline** — CI validates on every push/PR. Release triggers only on CI success on main via `workflow_run`. Prevents accidental releases from failed builds.
**Website package manager** — website CI uses pnpm with `website/pnpm-lock.yaml`; keep supply-chain guardrails in `website/pnpm-workspace.yaml`.
10
10
@@ -14,7 +14,7 @@
14
14
15
15
## What's done well
16
16
17
-
-**Validate job** — single job checks templates render, app links match across surfaces, VERSION is valid semver, CHANGELOG has an entry, deploy CLI flags are documented in cli-reference.md. Catches drift between docs and code.
17
+
-**Validate job** — single job checks the PWA renders, app metadata matches across surfaces, VERSION is valid semver, CHANGELOG has an entry, and deploy CLI flags are documented in cli-reference.md. Catches drift between docs and code.
18
18
-**System lab depends on lint+test** — syntax must be clean before spinning up Docker. Saves CI minutes on obvious failures.
19
19
-**PWA demo validation** — CI generates a demo PWA page and verifies all required files exist, SW is disabled for static hosting, and client HTML renders correctly.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+14-16Lines changed: 14 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,17 +4,7 @@ All notable changes to Meridian are documented here.
4
4
5
5
Format follows [Keep a Changelog](https://keepachangelog.com/).
6
6
7
-
## [Unreleased]
8
-
9
-
### Added
10
-
-**meridian-core JSON contract foundation** — Pydantic-backed `meridian.output/v1` envelopes, structured summary/error/event models, JSONL event primitives, JSON Schema export, and centralized secret redaction for automation and future UI clients
11
-
-**`meridian api schemas` / `meridian api schema NAME`** — discover and export JSON Schemas for the public meridian-core contracts used by CLI JSON output and future UI clients
12
-
13
-
### Changed
14
-
-**`meridian plan --json`** now emits the shared envelope shape with plan details under `data`; `status` is `no_changes` or `changed`, and the process exit code remains `0` for converged and `2` for changes pending
15
-
-**`meridian fleet status --json`** and **`meridian fleet inventory --json`** now emit the shared envelope shape while preserving stable command fields under `data`
16
-
17
-
## [4.0.0] - 2026-04-12
7
+
## [4.0.0] - Unreleased
18
8
19
9
### Remnawave compatibility matrix
20
10
This release pins a single tested version tuple. Upgrading any one component
@@ -24,43 +14,51 @@ without the rest is not supported — move the whole set together.
24
14
|---|---|
25
15
|`remnawave/backend`|`2.7.4`|
26
16
|`remnawave/node`|`2.7.0`|
27
-
|`remnawave/subscription-page`|`7.1.8`|
17
+
|`remnawave/subscription-page`|`7.2.1`|
28
18
|`remnawave` Python SDK |`2.7.1`|
29
19
| Xray-core client (test binary) |`26.3.27`|
30
20
| Realm (relay forwarder) |`2.9.3`|
31
21
| Pebble (system-lab ACME CA) |`2.10.0`|
32
22
33
23
### Changed
24
+
-**`meridian plan --json`** now emits the shared envelope shape with plan details under `data`; `status` is `no_changes` or `changed`, and the process exit code remains `0` for converged and `2` for changes pending
25
+
-**`meridian fleet status --json`** and **`meridian fleet inventory --json`** now emit the shared envelope shape while preserving stable command fields under `data`
34
26
-**Remnawave replaces 3x-ui** — modern panel with panel/node separation (NestJS + PostgreSQL + Valkey), proper REST API, built-in subscriptions, native multi-node support
35
27
-**Single `cluster.yml` replaces per-server `proxy.yml`** — fleet-wide manifest with panel URL, API token, nodes, relays. Client state lives in Remnawave's database, not locally
36
28
-**`client add` is one API call** — was ~400 LOC of SSH-tunneled curl, credential sync, and per-inbound client insertion
-**meridian-core JSON contract foundation** — Pydantic-backed `meridian.output/v1` envelopes, structured summary/error/event models, JSONL event primitives, JSON Schema export, and centralized secret redaction for automation and future UI clients
33
+
-**`meridian api schemas` / `meridian api schema NAME`** — discover and export JSON Schemas for the public meridian-core contracts used by CLI JSON output and future UI clients
-**`meridian fleet status/recover`** — panel health, node connectivity, relay status, user count, and reconstruct-from-panel when local state is lost
42
-
-**`meridian migrate`** — guided migration from 3.x (reads old proxy.yml, prints step-by-step plan)
43
36
-**`MeridianPanel` REST client** — wraps the official `remnawave` Python SDK (v2.7.1) with retries, credential redaction, and thread-local event loops for parallel workers
44
37
-**Config reliability** — corrupt YAML handling, version check, backup before mutations, disk-full error messages, external-edit guard (`cluster.save()` refuses to clobber if the file mtime advanced during a long-running apply), snapshot type validation
45
38
-**Reality keys persisted** — public_key and short_id saved in cluster.yml for connection testing
46
39
-**Declarative plan/apply workflow** — `cluster.yml` becomes desired state (`desired_nodes`, `desired_relays`, `desired_clients`, `subscription_page`); `meridian plan` prints a Terraform-style diff; `meridian apply` converges. Imperative commands (`deploy`, `node add`, `client add`) mirror their effect into `desired_*` when the list is non-null — hybrid sync, mixing the two modes is safe
47
-
-**Applied-state tracking** — every successful `apply` snapshots desired state into `cluster._extra["desired_*_applied"]`. The next plan distinguishes intentional removals (in applied → executes under `--yes`) from drift (not in applied → requires `--prune-extras=yes`). Closes the subtle bug where `--yes` silently skipped deliberate removals
40
+
-**Applied-state tracking** — every successful `apply` snapshots desired state into the typed `cluster.applied_state` model. The next plan distinguishes intentional removals (in applied → executes under `--yes`) from drift (not in applied → requires `--prune-extras=yes`). Closes the subtle bug where `--yes` silently skipped deliberate removals
48
41
-**`meridian plan --json`** — structured output for CI consumption; exit 0 = converged, 2 = changes pending, 1 = error. Stable JSON shape with typed `actions[].kind` values
49
42
-**`--prune-extras=ask|yes|no`** — explicit control over drift handling. Under `--yes`, `ask` downgrades to `no` (safety default); destructive actions still require one confirmation unless `--yes`
50
-
-**Parallel node provisioning** — `ThreadPoolExecutor` with `--parallel N` (default 4); per-worker `MeridianPanel` SDK instance, `threading.local()` event loops, `threading.RLock` on `cluster.save()` for safe concurrent writes
-**SSH multiplexing (`ControlMaster`)** — connection reuse across all SSH operations
52
45
-**Warp tri-state** — `DesiredNode.warp: None | False | True` (keep-current / disable / enable) with correct YAML round-trip (explicit `null`, not dropped; loader defaults missing key to `None`)
53
46
-**YAML null semantics** for `desired_*` and `subscription_page` — `null` means "unmanaged" (as documented); previously `desired_clients: null` collapsed to `[]` with `manage=True` and `subscription_page: null` loaded as `enabled=True`
54
47
-**Duplicate node-name validator** — `compute_plan`'s name→IP map and `find_node()` disagreed on duplicates, which could misroute relay `exit_node` references. Caught at load time now
55
48
-**Real-VM test harness** — optional `tests/realvm/` provisions real cloud VMs (Hetzner via `hcloud-python` SDK), runs full deploy + tier-α verification, tears down. Local-only (never in CI), opt-in via `make real-lab`. Foundation for a future `meridian deploy --create-vm <provider>` feature. Per-cloud `CloudProvider` abstract class under `src/meridian/infra/providers/`
56
49
-**NET_ADMIN capability** on remnawave-node container — required by panel 2.6.2+ for Torrent Blocker, IP Control, and related plugins. Without it, those features silently no-op
57
50
-**Subscription-page lifecycle via cluster.yml** — enable/disable the Remnawave subscription container declaratively; `docker compose up -d --no-recreate` on subpage-only apply to avoid incidental panel restart
51
+
-**Hysteria2 UDP/443 fallback** — available after the TCP transports in subscription ordering, with matching host and firewall configuration
58
52
-**`ConfigureFail2ban` + fail2ban package wired in both pipelines** — fail2ban is now actually installed and started on every hardened deploy. Previously `build_setup_steps` had an operator-precedence trap (`InstallPackages(REQUIRED_PACKAGES + ["fail2ban"] if harden else None)` parsed as `(REQUIRED + fail2ban) if harden else None`, skipping all packages on `--no-harden`) and `build_node_steps` (used for redeploy) lacked the step entirely
59
53
-**Smart xray readiness polling** in system-lab — polls node API port 3010 + 5s grace for Reality inbound init, replacing a blind `sleep 30`
60
54
55
+
### Fixed
56
+
-**Safe fleet recovery** — recovered inbounds now use stable protocol keys and the current cluster schema; Reality public keys are derived from preserved private keys, and redeploy refuses incomplete key material instead of silently rotating credentials
57
+
61
58
### Removed
62
59
-**3x-ui panel** — PanelClient, ConfigurePanel, CreateInbound, all SSH-tunneled curl API calls
63
-
-**Per-server proxy.yml** — replaced by cluster.yml (kept only for `meridian migrate` compatibility)
60
+
-**All pre-v4 migration and compatibility paths** — v4 starts from typed `cluster.yml` and `servers.json` state; the old migrate command, installer/setup shims, per-server `proxy.yml` credentials, legacy registry import, and 3x-ui cleanup step are gone
61
+
-**Legacy local connection-page renderer** — the server-hosted PWA is the only connection-page implementation
64
62
-**Local client state** — no more UUID storage, credential sync, SCP rollback
0 commit comments