简体中文版本请展开页面底部的「简体中文」。
2.0 is the first stable release since the 1.6 series. It rewrites the frontend, rebuilds how the backend manages state and the core, and adds traffic analytics, Profile pipeline inspection, a standalone widget, diagnostics and crash reporting.
These notes compare against v1.6.1. Implementations that landed during the Beta and RC cycle and were later replaced are not listed separately.
Read Before Upgrading
- Your configuration is migrated automatically. On first launch, the old
verge.yaml,profiles.yamland related files are split and migrated into new per-domain configuration files. The configuration directory andstorage.dbare backed up before migration; if migration fails, the startup dialog offers "Open backup directory", "Open migration log" and "Quit". Old settings keep their meaning wherever possible: for example,auto_close_connection: falsebecomes "Do not close connections when switching proxies", and a non-random mixed port becomes a fixed port. We still recommend backing up the configuration directory by hand before a major upgrade; afterwards, you can create a backup from Settings at any time. - Release targets are narrowed to six: x86_64 and aarch64 for each of Windows, Linux and macOS. i686 builds for Windows/Linux and Linux ARMv7 (armel/armhf) builds are no longer provided.
- The CPU must support hardware AES: x86_64 needs AES-NI (Intel Westmere from 2010 or later, AMD Bulldozer from 2011 or later); aarch64 needs the ARMv8 AES extension. Some ARM devices without it, such as the Raspberry Pi 4/5, cannot run 2.0.
- The minimum macOS version is now 12.6 (11.0 in 1.6).
- Service mode requires nyanpasu-service 2.0.1 or later. Older services are rejected by the version check rather than falling back to the old protocol; update the service from System Settings when prompted.
portandsocks-portin Profiles, Merge/Overlay and scripts are no longer passed to the core. Likemixed-port, both ports are now managed in Clash settings and are removed when unset. This prevents a subscription's ownport: 7890from taking over the mixed port (#5720).- The Profile model has changed. "Multiple selected Profiles + Chain" is split into a single current Config plus Transforms: merging several subscriptions is expressed with a Composition Config, Merge is renamed Overlay, and the global Chain becomes Global Transform. Remote / Local are no longer Profile types but a source property of each Profile (see "Profiles and the Pipeline"). Migration converts existing data automatically.
- Clash Premium is deprecated and will be removed in a future release. It still works in this release; core management and the dashboard mark it as deprecated, and switching to it shows a notice.
- Third-party dashboards should use the HTTP external controller settings provided by the app. The core's named pipe / Unix socket control channels are allocated and authorized per instance by the runtime and are no longer a stable, customizable interface.
New Features
Redesigned Interface
- The main interface is redesigned in Material You, and the old interface has been removed. Components are built on our own
@nyanpasu/ui(Radix primitives + Tailwind CSS) rather than re-theming the old pages. - The dashboard is made of freely arranged widgets; layouts can be saved and each widget configured on its own. When the window is resized, the layout for the new size is used.
- Theming: follow the system accent color, or pick a color from the HCT palette with live preview; light / dark / follow system; custom CSS or LESS. The default theme color is
#3e64a7. - Inter Variable is bundled and the CJK font fallback order is adjusted. The page's
langattribute follows the app language, so Han characters use the glyphs of the selected language rather than the system locale. - Responsive sidebar and narrow-window navigation, directional page transitions, per-platform title bars (Windows / macOS / Linux) and configurable window decorations. Linux no longer uses the native title bar by default.
- The title bar menus (File / Settings / Help) are now a unified menu bar with keyboard navigation and switching between open menus.
- Settings are grouped by category, and pages with many items are split into subpages.
- The About page lists open source licenses.
Traffic Analytics
The new Traffic Analytics page lets you review historical traffic and track down anomalies:
- View traffic by overview, connection path, location, device and process; rankings can be weighted by traffic or by connection count. After filtering on a dimension, its other candidates stay in the ranking for comparison.
- Traffic is recorded per Profile, bucketed by time, and expired data is cleaned up automatically. Closed connections can also be browsed page by page with filters.
- The map is shaded by traffic share. Regions are resolved with a country index bundled with the app (built from the core's geo databases), and each region shows how it was located.
- DIRECT traffic and local sources can be located by probing the public IP. The probe requires explicit consent and is never sent while TUN is enabled.
- The Rules, Connections and Traffic pages link to each other, carrying filters along, and you can return to the original page.
- Data is stored in the new time-series layer
nyanpasu-tsdb(see "Architecture"). Traffic recorded during Beta/RC is imported automatically on upgrade.
Profiles and the Pipeline
-
Type and source are separate: in 1.6 a Profile was one of Remote, Local, Merge or Script, and only configuration files could come from a remote subscription. 2.0 separates "what it is" from "where it comes from". Types are Config (a single configuration file, or a Composition combining several sources) and Transform (YAML Overlay, JavaScript / Lua script). The source is a separate property of each Profile and can be:
- Remote: downloaded from a URL and synced on an interval;
- Managed locally: the file is managed by the app and edited in the app;
- Linked local file: references a file of your own, either as a "symlink" (references the original file directly; on Windows this needs Developer Mode or administrator rights) or a "mirror" (keeps a copy and syncs it when the original changes).
Overlays and scripts can therefore be synced from a remote source like subscriptions, or linked to files you maintain elsewhere.
-
Pipeline: Overlay, JavaScript and Lua Transforms can be attached after a Config, and Global Transforms apply to every Config. The pipeline can be reordered by drag and drop.
-
Inspect: a full-height step browser shows how the configuration is generated. Each step has a snapshot, a diff against the previous step, a list of changed fields and the step's log, with the effective nodes and each step's highest log level marked. The final view matches the configuration the core actually loads. The open document tab and step filters are remembered.
-
Profile folders: create folders and organize Profiles by drag and drop or a "Move to" menu; deletion can be undone.
-
Preview before importing from a URL: the content is downloaded first, classified as a Config, Overlay or script from its response headers and content, and imported after you confirm the type and source.
-
Redesigned Profile cards and detail pages; subscriptions show their remaining traffic quota. All subscriptions can be updated at once, with sync status and run history; the update interval is hidden when auto-update is off.
-
clash://install-configdeep links can specify a name and share the quick-import flow. Links are queued in the backend and imported in order once the main window has loaded, so links arriving during a page reload or before the window loads are not lost. -
Subscriptions: Remnawave HWID, syncing the Profile name from response headers, hidden proxy groups from subscription metadata, and IP hostnames in subscription URLs.
-
include-allin proxy groups is expanded the way Mihomo does it and can be toggled in Clash settings. -
The generated configuration keeps the key order of the source files. 1.6 reordered top-level keys by a fixed field table, so the generated configuration did not match the layout of the source. Nested maps keep their order too, which matters to the core for fields such as
dns.nameserver-policy. -
Scripts: JavaScript can import JSON/plain-text modules and built-in helper modules, runs in memory and keeps stack traces; both JavaScript and Lua have
consoleoutput, and Lua keeps the original key order after processing. -
When saving fails, the error names the Profile and the file.
Proxies, Connections and Rules
- Proxies: proxy groups are listed in the sidebar, can be put in folders and reordered by drag and drop, and the layout is saved per Profile; frequently used groups can be pinned. Nodes within a group can be searched, sorted and filtered. Latency tests use each group's own test URL with a configurable timeout; node cards show recent latency history; group headers show the number of available nodes and the current selection chain (e.g.
A › B › node). Health checks can be triggered for Providers. "Close connections when switching proxies" now has three levels: off / this group only / all. - Connections: a Closed tab, configurable columns, filtering by traffic dimension and value range, connection details and totals; sorting and scrolling through large lists are faster.
- Rules: the rule list is virtualized, can be filtered by proxy, and shows each rule's current connection count and traffic.
- Providers: a new dedicated Providers page.
Core
- Adds the Meow (
meow-rs) core with its own Meow Alpha channel, and Clash Rust Alpha, including Windows ARM64. - Alpha cores read the build currently in the upstream rolling release on every update check, so the version manifest no longer points at a deleted file after an upstream update, which caused 404 downloads.
- Core updates verify the archive's SHA-256 and the binary's version; "Reinstall" is offered when an installed core cannot report its version.
- A new core management view shows the core status, the control channel (HTTP / named pipe / Unix socket) and the service mode status. The control channel can be chosen in Settings, and the view also shows the channel actually in effect.
- With the Meow core, core updates also install its bundled
meow-cliand agent skill. A new AI page in Settings provides a one-line prompt you can give to an agent such as Claude Code or Codex to install the skill. - On macOS with TUN enabled, taking over and restoring the system DNS is part of the core transaction. The original DNS is persisted before any change, so it can be restored even after the app exits abnormally.
- When several instances run at once (for example a development build and a release build), one instance no longer stops a core that another instance started through the service.
- Service mode is now a preference: the service runs the core when it is ready; when the service is not installed, stopped or incompatible, the core runs locally and Settings shows a notice. Neither startup nor saving settings installs or starts the service automatically, so no unexpected UAC prompt appears; once the service is ready again, the next startup or an explicit action uses it again.
- Local mode and service mode share the same app-managed core data directory owned by the current user, so caches stay writable after switching modes.
- On Windows the service is controlled over a named pipe. Stopping the core first sends Ctrl+C through the service, so a force-killed Meow no longer leaves adapter DNS behind. Toggling Meow's TUN alone first tries a hot update and reads it back to confirm, restarting the core only if that fails.
- TUN
auto-routecan be managed separately; on Unix, TUN permissions are checked and granted automatically when needed.
System Proxy and Network Settings
- Adds a PAC mode with download, validation and fallback on failure.
- The mixed, SOCKS5 and HTTP ports can each be enabled with a strategy: fixed, random, or fall back to a free port when occupied. When the port actually bound at runtime differs from the configuration, both are shown. A non-random mixed port from 1.6 stays "fixed" after migration.
- The system proxy bypass list falls back to the default when empty.
- In 1.6, "Auto close connections" was a single switch. 2.0 splits it into three settings that each decide whether existing connections are closed: when switching proxies (off / current proxy group only / all connections), when switching Profiles, and when switching routing modes. The old setting is migrated automatically.
- New DNS cache management and external controller settings pages; fields such as
unified-delayandtcp-concurrentcan be handed over to the Profile when needed. Fields handed over to the Profile keep the Profile's values even when Clash field filtering is on.
Logs, Diagnostics and Crash Reports
- The log viewer combines app, service and core logs, with search highlighting, date filtering, JSON highlighting, loading history on scroll and live follow.
- App logs rotate by file size and local date. Core log rotation and compression can be changed in Settings and take effect immediately; session logs rotate within a disk budget and are compressed with preset and trained dictionaries.
- Frontend warnings and errors are also written to the app log.
- Diagnostics: "Report an issue" collects environment information (system, CPU/GPU, WebView, current core) along with recent app and core logs, and shows its progress. The logs are redacted and packed into a ZIP (the latest 5 are kept) that can be revealed in the file manager and dragged into an issue. Redaction removes user info and query parameter values from URLs, credential-like fields, Bearer tokens and home directory paths.
- Crash reports: on a fatal panic, a separate native window (built with Slint, independent of the main WebView) shows the full report, scrollable and copyable, and can open a prefilled issue in one click. Crashes include the diagnostics as well. Stack frames are recorded as module offsets, and Windows releases archive the symbol files so they can be symbolized afterwards. The report window follows the app language.
Standalone Widget, Tray and Windows
- Standalone network widget: a lightweight native window (Slint) running as a child process of the app, without loading the main WebView. It comes in large and small styles and shows upload/download speeds and cumulative traffic. Like the tray icon, its logo can switch with the proxy state (no proxy / TUN / system proxy), using either the tray icons or a separate icon set. Measured on a Windows release build: about 24 MiB working set and 3 threads.
Tray
- WebView tray menu: a new Material You tray panel that can open the main window, toggle the system proxy and TUN, switch between Rule / Global / Direct / Script modes, pick proxy groups and nodes level by level, copy Shell / Cmd / PowerShell environment variables, open the data / config / core / log directories, restart the app or the core, and quit. The native menu is still available and can be selected in Settings; Windows defaults to the WebView menu, other platforms to the native menu.
- Icons: Windows offers two presets, "Minimal cat" and "Mascot", plus a custom editor: drag built-in icons onto the no proxy / TUN / system proxy states (keyboard operation is supported), or upload an image for each state. macOS keeps using monochrome template icons.
- The tray can show text and live upload/download speeds; macOS supports colored icons.
- Proxy nodes in the native tray menu are identified by "group + node", so duplicate group names or renamed nodes no longer check or click the wrong node.
- The tray menu no longer steals focus when it opens.
Windows
- A new window manager handles creating, showing, hiding and destroying windows. Every window is created hidden and shown only once its page is ready, so editors and the tray menu no longer flash a blank window; a window not ready within 10 seconds is shown as a fallback. Rapidly opening/closing from the tray or a hotkey no longer depends on the order in which events arrive.
- Closing can be set to "destroy" or "hide": set a global value, then let the main window, editors and tray menu each inherit it, destroy or hide. The old tray menu close setting is migrated automatically.
- The Windows main window is no longer created as a transparent window. A transparent window allocates a window-sized bitmap on every repaint; without it, an open window uses one window-sized allocation less (about 30 MB for a 3840×2064 window).
- The Profile editor and the custom CSS editor open in separate windows.
- When a window is hidden to the tray or minimized, its WebView is marked invisible and asked to reduce memory usage, and animations stop rendering in the background.
Updates and Distribution
- Switch between the Stable, Beta and Nightly update channels. Switching from Beta back to Stable keeps the current version until a newer stable release appears.
- The update dialog lists the release notes of every version skipped since the current one, rendered as GitHub-flavored Markdown.
- The priority of download sources is configurable (with new mirrors such as ghfast), and download speed tests sample over a fixed time window. The app and the core shut down in order before the installer starts.
- The Windows installer and the portable build each come in two variants: a standard one using the system WebView2, and one bundling a fixed-version WebView2.
- Release artifacts are also uploaded to SourceForge and the Internet Archive as mirrors.
- The NSIS installer gains a sidebar image, and the macOS DMG a background and icon layout.
Windows Loopback Exemption Tool
- The old UWP loopback tool (
enableLoopback.exe, a .NET Framework 4 WinForms program downloaded aslatestfrom a third-party repository, with no source, version or checksum) is replaced by our own enable-loopback, written in Rust and WinUI 3. - It fully reproduces the original tool: list AppContainers with search, sorting, multi-select and copy, save exemptions for checked entries, and a command-line mode (
-all,-none,-allow,-deny). It fixes the original tool's saving defect: when a write fails, unsaved changes are kept and can be retried directly. - The interface follows the app language and supports English, Simplified Chinese, Traditional Chinese, Japanese, Korean and Russian.
- The tool's version is pinned with the submodule and verified against the GitHub release's SHA-256 after download. On launch it checks for the Windows App Runtime and offers to install it from the Microsoft Store when missing; systems without the Store (such as LTSC) use the official download instead.
- The app list builds rows only for the visible area, cutting the private working set at startup from about 107 MiB to 71 MiB (v0.1.4).
Languages
- Adds Japanese, Korean and Traditional Chinese (including the NSIS installer). Supported languages are now English, Simplified Chinese, Traditional Chinese, Japanese, Korean and Russian.
- The interface language is chosen from the system language on first launch.
- The Simplified Chinese, Traditional Chinese, English and Korean translations have been reviewed string by string.
Architecture
This section is mainly for contributors, and it also explains where many of the stability improvements come from.
From Global Singletons to Explicit Composition
- Process-wide global singletons such as
Config,CoreManager,HandleandLoggerare all gone. Dependencies are injected through constructors, builders, function parameters or actor startup arguments, and the object graph is assembled in a composition root at startup. The few remaining process-widestatics are registered and checked by CI. - Long-lived mutable state (configuration, Profiles, the core, the service, WebSocket streams, the tray, hotkeys, update downloads, traffic recording and more) is owned serially by actors. Deterministic logic such as configuration generation, validation and runtime configuration building stays as pure functions independent of Tauri.
- The application layer exposes domain operations through
NyanpasuClient. It is not a service locator and does not expose actor references. Windows, the tray, dialogs, the file system, the network and so on are reached through ports and adapters, and business logic does not use Tauri types directly. UI-independent path resolution, runtime and platform capabilities have moved into neutral crates such asnyanpasu-coreandnyanpasu-platform, preparing for non-GUI frontends such as a CLI.
Configuration Layer
- Configuration is split by domain into the typed
nyanpasu-config: application settings (Application), window and session state (SessionState), Clash settings (ClashConfig) and Profiles are persisted separately and each managed by its own actor, instead of sharing one global object that anything could read and write. Every configuration file carries a schema revision; old data is converted by a one-time migration, backed up automatically beforehand and checked for state consistency afterwards. - The runtime configuration is generated by pure functions from typed snapshots: Profile sources → pipeline → guarding and filtering of managed fields → post-processing → final configuration, with a snapshot and changes recorded at each step. "What was saved", "what was generated" and "what the core actually loaded" are recorded separately.
nyanpasu-stateuses TCC-like, inversion-of-control state transactions: configuration actors only build candidate values, and the state layer orchestrates prepare, persistence, CAS commit and notification. Participants that affect the running state (the running configuration, switching cores, switching service mode, etc.) join the same transaction through Try / Confirm / Cancel: if Try fails, the source configuration is not committed; if persistence fails, Cancel restores the previous state. Peripheral effects such as the tray, the UI and the system proxy are reconciled after the commit, and their failures are shown separately as "committed but not converged" rather than as "configuration not saved".- Every commit produces a receipt and a state event, so the UI can show whether the configuration has converged and which operations have unconfirmed results, with retry. Commit events are pushed to every window and HTTP client, and the frontend re-reads only the data that actually changed.
Core Management (nyanpasu-runtime)
- The core lifecycle is owned by the new Core Manager. Each core instance has a monotonically increasing epoch and counts as started only after passing a health probe; a supervisor restarts it with backoff after crashes; the runtime configuration is held privately by the manager with revision-based optimistic concurrency control. Configuration changes are classified as Noop / Patch / Reload / Restart / Switch and rolled back on failure.
- When the core and configuration support it, switching cores first starts the new core with a configuration that listens on no inbound ports and probes it, then stops the old core and restores the listeners. This moves the seconds-long startup out of the downtime window; the port handover still causes a brief interruption. When the conditions are not met (e.g. an HTTP controller or listener conflicts), it falls back to a direct switch. When the old process cannot be confirmed to have exited, the manager enters quarantine instead of starting a conflicting instance.
CoreControlunifies the semantics of local and service mode: validation, revision CAS, classification, execution, verification, rollback and publication happen in oneReconciletransaction; operations run through a bounded serial queue and are idempotent by OperationId. A caller disconnecting or giving up on waiting does not interrupt an operation that has started. The service hosts the same completeCoreControl, not a reduced backend.- The in-app
CoreActoronly selects the local or service endpoint, forwards operations and projects state; it no longer keeps a second copy of the lifecycle state.ServiceActorhandles installing the service, version compatibility, probing, reconnecting and uninstalling. Switching between local and service is an explicit handover of control guarded by a generation. - The service protocol is upgraded to v2: errors are returned as structured
CoreErrorKinds, state is pushed as full snapshots, and the event stream resynchronizes automatically after falling behind (Lagged). Configuration is transferred as content and digest instead of a path local to the service. The Windows core named pipe gains access authorization, and service logs no longer record environment variable values. - Clash API access is bound to a specific core instance; old handles become invalid when the instance is replaced, so requests never reach a core that has already been replaced.
Unified RPC
- App commands are declared with
#[nyanpasu_macro::rpc], and Tauri IPC and the optional local HTTP server share the same application layer. Frontend types are generated by Specta, and the frontend calls the backend only through@nyanpasu/rpcand@nyanpasu/query. - Commands are classified as queries or mutations by their actual side effects; errors cross the transport as structured data and their details can be copied. Connection details are sent only to pages that subscribe to them.
- The local HTTP server is off by default, binds only to loopback, generates new access credentials on every start and checks Host/Origin.
New Building Blocks
nyanpasu-tsdb: a columnar time-series layer written for traffic analytics. Data is bucketed by time, labels are dictionary-encoded and stored in column chunks; queries run on snapshots; retention cleanup, compaction and space reclamation run as background maintenance tasks; all memory allocated in proportion to data volume counts against a memory budget; redb is the persistence backend.nyanpasu-local-channel: a typed, bidirectional local channel between parent and child processes, with access tokens, type fingerprint checks, a frame size limit and platform ACLs. The standalone widget talks to the main app through it.- Background jobs (subscription updates and others) are scheduled by actors in the runtime; run records are written to a transactional redb journal, and logs are captured per job.
Frontend Engineering
- The frontend is split into source packages such as constants, utils, hooks, platform, rpc, query, theme and ui, with the dependency direction between packages enforced by a check script.
- Main stack: React 19, TanStack Router / Query / Table, Tailwind CSS 4 (replacing Sass), Paraglide JS (replacing the previous i18n solution), Monaco 0.56 (loaded on demand, kept out of the main bundle), es-toolkit (replacing lodash-es), Oxlint (replacing ESLint); repository scripts moved to Deno.
- UI state storage: in 1.6, UI state such as the dashboard, proxy group order and theme was stored by jotai atoms in each window's own localStorage. 2.0 writes it to a KV store in the backend's
storage.db(redb), read and written by the frontend throughuseKvStorage, which works much likeuseState: within a window, each key is read from the backend once and then kept up to date by change events; writes show up immediately in every component using the key and are committed in call order; every read, write and change event carries a revision, and a backlog of events triggers a resync. localStorage serves only as a first-frame cache. This state is therefore shared across windows and HTTP clients and included in configuration backups. - Backend events: events are exported as tauri-specta types, generated into bindings together with the commands, and can be bridged to HTTP. After a configuration commit, the state change event says what kind of data changed (application settings, Clash settings, Profiles, and which Profiles), so the frontend refreshes only the affected queries.
Development and Verification
- Architecture constraints are checked by scripts:
lint:architecture-ledgerforbids new global service singletons and requires every process-widestaticto be registered with its purpose;lint:backend-boundarieschecks the dependency direction of backend crates (neutral crates must not depend on Tauri, egui or Slint);lint:frontend-boundarieschecks the dependency direction between frontend packages. - Testing: actors are tested through typed clients with fake adapters; a new fake-core can stand in for a real core, and the runtime also has integration tests against real cores; the frontend uses Vitest unit and browser tests.
- Performance: page benchmarks can count renders and the longest main-thread busy time and emit profiles and traces;
deno task bench:abruns A/B comparisons alternating between two commits. The backend providestrace-chromeanddhat-heapprofiling features. - In-process requests and replies always wait for the real result; timeouts exist only at network and IPC boundaries, and a caller giving up on waiting does not cancel work that has started.
- Incompatible change for API callers:
clash_api_get_providers_proxiesreturns only Provider summaries (withproxyCount), no longer the full node list,testUrlandexpectedStatus(#5831). - Development standards live in
docs/development/: architecture and ownership, unified RPC, testing and review, workflow, Rust and TypeScript code style, frontend packages and repository scripts.
Performance
The numbers below come from A/B comparisons of specific changes made during development, under differing test conditions. They cannot be added up and do not represent an overall comparison with 1.6.
| Scenario | Test conditions | Before → after |
|---|---|---|
| Windows main window | No longer created as a transparent window, 3840×2064 window | One fewer repaint bitmap of about 30 MB while the window is open (scales with window size) |
| Standalone widget (Windows) | Release build, launched from the app subcommand | Working set about 150 → 24 MiB; threads about 32 → 3 |
| Standalone widget (macOS) | Apple M3, 2x scaling, 1 update/s, software rendering vs. femtovg | Memory footprint about 77 → 16 MiB |
| enable-loopback | v0.1.4, building only rows in the visible area | Private working set at startup about 107 → 71 MiB |
| Runtime configuration snapshots | Windows, DHAT, same configuration, window open for 90 s | Rust heap (at exit) 10.99 → 8.23 MiB; snapshots 3.63 → 0.61 MiB |
| Windows background memory | Main window closed, 1 hour of synthetic proxy load, Segment Heap enabled | Private bytes 43 → 32 MiB |
| Traffic report query | 500,000 rows of hourly data, full report | About 72 → 9 ms (vs. the initial tsdb implementation); allocations per request 21.8 → 0.77 MiB |
| Connections page | Chromium, 4x CPU throttling, 6,000 connections sorted by download speed | Longest sampled frame 50–67 → 17–33 ms; longest task on open 301–375 → 108–113 ms |
| Switching proxy groups | 30 groups × 1,500 nodes, Chromium, 4x CPU throttling | Longest frame 73 → 27 ms |
| Profile Inspect | WebView2, in-app median | Open 181 → 43 ms; Output tab 175 → 15 ms |
| Large diff | 1,500 hunks, Chromium | Longest task 327–422 ms → no task over 50 ms; highlighting 1.6–2.1 s → about 0.1 s |
| Opening a large local Profile | Large YAML file | Main-thread scripting 843 → 319 ms (YAML parsing moved to a worker) |
| Connection data decoding | 150 connections per frame | Bytes allocated per request down about 47%–55% |
Notes:
- Windows Segment Heap trades CPU time for memory: in two 30-minute runs, CPU time was 1.3x and 2x that of the default heap, both below 0.5% of a single core. It does not affect WebView2 processes, and Windows versions before 10 2004 ignore the setting.
- On Linux the widget still renders with femtovg (OpenGL), so the widget numbers above do not apply to Linux.
- DHAT counts only the Rust allocator, not WebView2, the core process or native system allocations. Most frontend numbers come from large synthetic data sets with 4x CPU throttling, for comparing long tasks and jank; they do not represent absolute frame rates on real devices.
- Other memory changes: the log buffer shrinks from 128,000 lines to 4,096 (saving about 3.8 MiB); proxy fingerprints use streaming hashes instead of keeping about 2 MiB of JSON resident; the Provider cache keeps summaries only; the shared tokio runtime is capped at 4 worker threads.
Notable Fixes
- When a subscription's
portequaled Nyanpasu'smixed-port, the core could grab the HTTP port first on a cold start, so the mixed port failed to listen and the dashboard wrongly reported "port in use by another program" (#5720). - Enabling IPv6 had no effect with Clash Rust: a built-in compatibility script removed the top-level
ipv6, which clash-rs actually reads (#6019). - After a window was hidden to the tray or minimized, its WebView kept rendering at the display refresh rate, with the renderer and GPU processes using about 0.2 of a core (#5817).
- Issues when moving windows between monitors with different scaling, restoring window state after minimizing, and Linux window management.
- Single-instance detection interfering across Windows users and configuration directories.
- On Windows shutdown or sign-out, the system now waits for the app to finish its clean exit before continuing.
- Registry-related commands on Windows no longer flash a PowerShell window.
- Autostart on Linux not working under desktop environments such as KDE; GTK icon cache updates failing.
- After restarting the core, the routing mode reverted to the old value in the configuration file instead of keeping the user's choice.
- Inconsistent Clash Rust version formats breaking version display and comparison.
- NSIS upgrades across versions now update in place by default; auto-update no longer replaces the NSIS installer with the updater executable.
- Settings such as
allow-lanlost after a restart; multiple selected entries in the same proxy group in the tray; the dashboard freezing after the window was hidden. - Background jobs, the internal HTTP server and the core shut down in order when the app exits, the main thread panics, a workflow terminates abnormally, or the update installer is launched.
Dependencies and Toolchain
Only migrations that affect users, platforms or architecture are listed; routine version bumps are omitted.
- Tauri 1 → 2: all window, tray, dialog, clipboard, updater, shell and path APIs migrated.
- rustls replaces OpenSSL, reqwest replaces isahc: no more dependency on the system OpenSSL.
- Boa 0.22, mlua 0.12: for JavaScript / Lua Transforms.
- Specta 2: type generation between frontend and backend.
- Slint: for the standalone widget and the crash report window, avoiding loading a WebView and GPU stack for these small windows. Windows / macOS use software rendering (softbuffer); Linux uses femtovg.
- redb and our own nyanpasu-tsdb: for KV storage and traffic time-series data respectively.
- gxhash: hardware-accelerated hashing used for log indexing and similar tasks, and the reason the CPU must support hardware AES.
- Frontend dependency migrations are covered under "Architecture → Frontend Engineering".
Thanks
Thanks to everyone who contributed to 2.0, including @greenhat616, @keiko233, @3gf8jv4dv, @Slinetrac, @4o3F, @lmmqxyx404, @xmh0511, @kolya13245, @moduvoice, @latin-1, @MNDIA, @Jimie165, @yokinanya, @trhao99, @temp-maker-temp, @legiz-ru, @gengjiawen, @Sn0wo2, @SherkeyXD, @Rbqwow, @C4a15Wh, @Bihrys, @ArakawaHenri, and everyone who filed issues and helped test.
Full Changelog: v1.6.1...v2.0.0
2.0 是自 1.6 系列以来的第一个 stable 版本。本版本重写了前端界面,重建了后端的状态管理与内核管理方式,并新增流量分析、Profile 处理链检查、独立 widget、诊断与崩溃报告等功能。
本文对照的基线是 新增 Traffic Analytics 页面,用于回看历史流量并定位异常:
类型与来源分离:1.6 的 Profile 类型是 Remote、Local、Merge、Script 四选一,只有配置文件能从远程订阅。2.0 把“是什么”和“从哪来”拆开:类型分为 Config(单个配置文件,或由多个来源组合的 Composition)和 Transform(YAML Overlay、JavaScript / Lua 脚本);来源是每个 Profile 的独立属性,可以是:
因此 Overlay 和脚本也能像订阅一样从远程同步,或直接链接到用户在别处维护的文件。
处理链:Config 之后可以挂接 Overlay、JavaScript、Lua 三类 Transform,并可设置对所有 Config 生效的 Global Transform。处理链支持拖拽排序。
Inspect:以全高的步骤浏览器展示配置的生成过程。每一步都有快照、相对上一步的 diff、变更字段列表和步骤日志,并标出最终生效节点和每一步的最高日志级别。最终视图对应内核实际加载的配置。打开时的文档标签和步骤筛选会被记住。
Profile 文件夹:可以新建文件夹,用拖拽或“移动到”菜单整理 Profile,删除后可撤销。
从 URL 导入前先预览:先下载内容,再根据响应头和内容判断它是 Config、Overlay 还是脚本,由用户确认类型与来源后导入。
Profile 卡片和详情页重新设计,订阅显示剩余流量配额;订阅可全部一键更新,并显示同步状态和历史运行记录;自动更新关闭时会隐藏更新间隔。
订阅相关:支持 Remnawave 的 HWID、从响应头同步 Profile 名称、订阅元数据中的隐藏代理组,以及订阅 URL 使用 IP 主机名。
代理组的 生成的配置保持源文件中的键顺序。1.6 会按固定字段表重排顶层键,导致生成的配置与源文件的布局对不上。嵌套映射同样保持原有顺序, 脚本:JavaScript 支持导入 JSON/纯文本模块、内置辅助模块、内存执行并保留调用栈;JavaScript 与 Lua 都有 保存失败时,错误信息会注明是哪个 Profile、哪个文件。
这一部分主要面向贡献者,也解释了很多稳定性改进的来源。
以下数据来自开发期间针对具体改动的 A/B 对比,测试条件各不相同。它们不能相加,也不代表与 1.6 的整体对比。
说明:
只列出影响用户、平台或架构的迁移,常规版本更新从略。
感谢参与 2.0 开发的所有贡献者,包括 @greenhat616、@keiko233、@3gf8jv4dv、@Slinetrac、@4o3F、@lmmqxyx404、@xmh0511、@kolya13245、@moduvoice、@latin-1、@MNDIA、@Jimie165、@yokinanya、@trhao99、@temp-maker-temp、@legiz-ru、@gengjiawen、@Sn0wo2、@SherkeyXD、@Rbqwow、@C4a15Wh、@Bihrys、@ArakawaHenri,以及提交 issue 和参与测试的用户。
完整变更:v1.6.1...v2.0.0
简体中文
v1.6.1。Beta 与 RC 期间先合入、后又被替换的实现不单独列出。
升级前请先阅读
verge.yaml、profiles.yaml 等拆分并迁移为新的分域配置。迁移前会自动备份配置目录和 storage.db;迁移失败时,启动对话框提供“打开备份目录”“打开迁移日志”和“退出”。旧配置的语义尽量原样保留,例如 auto_close_connection: false 迁移为“切换代理时不断开连接”,非随机的混合端口迁移为固定端口。跨大版本升级前,仍建议先手动备份一次配置目录;之后也可以在设置中随时创建备份。
port、socks-port 不再传给内核。 这两个端口改为与 mixed-port 一样由 Clash 设置统一管理,未设置时会被移除。这样可以避免订阅自带的 port: 7890 抢占混合端口(#5720)。
新功能
重新设计的界面
@nyanpasu/ui(Radix primitives + Tailwind CSS),不是在旧页面上替换主题。
#3e64a7。
lang 属性跟随应用语言,汉字会按所选语言而不是系统区域显示对应的字形。
流量分析
nyanpasu-tsdb 保存(见“架构”一节)。Beta/RC 期间记录的流量数据会在升级时自动导入。
Profile 与处理链
clash://install-config 深度链接导入可以指定名称,并与快速导入共用同一流程。链接先在后端排队,由主窗口加载后依次导入,页面重载或窗口尚未加载时到达的链接不会丢失。
include-all 会按 Mihomo 兼容的方式展开,可在 Clash 设置中开关。
dns.nameserver-policy 这类字段的顺序对内核是有意义的。
console 输出,Lua 处理后保持原有的键顺序。
代理、连接与规则
A › B › 节点)。可以对 Provider 触发健康检查。“切换代理时断开连接”改为三档:关闭 / 仅本组 / 全部。
内核
meow-rs)内核,以及独立的 Meow Alpha 通道;新增 Clash Rust Alpha,包括 Windows ARM64。
meow-cli 和 agent skill,设置中新增的 AI 页面提供一句话,交给 Claude Code、Codex 等 agent 即可安装该 skill。
auto-route 可单独管理;Unix 上会检查 TUN 权限并在需要时自动授权。
系统代理与网络设置
unified-delay、tcp-concurrent 等字段可以按需交给 Profile 管理。即使开启了 Clash 字段过滤,指定交给 Profile 的字段也会保留 Profile 中的值。
日志、诊断与崩溃报告
独立 widget、托盘与窗口
托盘
窗口
更新与分发
Windows 回环豁免工具
enableLoopback.exe,一个 .NET Framework 4 WinForms 程序,从第三方仓库下载 latest,没有源码、版本和校验)改为自研的 enable-loopback,使用 Rust 与 WinUI 3 编写。
-all、-none、-allow、-deny)。修复了原工具的保存缺陷:写入失败时保留未保存的修改,可以直接重试。
语言
架构
从全局单例到显式组合
Config、CoreManager、Handle、Logger 等进程级全局单例已全部删除。依赖改由构造器、builder、函数参数或 actor 启动参数注入,对象图在启动时的 composition root 中组装。仍保留的少数进程级 static 都有登记,并由 CI 检查。
NyanpasuClient 对外提供领域操作。它不是 service locator,也不暴露 actor 引用。窗口、托盘、对话框、文件系统、网络等通过端口和适配器接入,业务逻辑不直接使用 Tauri 类型。与界面无关的路径解析、运行时和平台能力已拆到 nyanpasu-core、nyanpasu-platform 等中立 crate,为后续 CLI 等非 GUI 前端做准备。
配置层
nyanpasu-config:应用设置(Application)、窗口与会话状态(SessionState)、Clash 设置(ClashConfig)和 Profiles 分别持久化、分别由各自的 actor 管理,不再共用一个可随意读写的全局对象。每个配置文件都带有 schema revision,旧数据由一次性迁移转换,迁移前自动备份,迁移后检查状态一致性。
nyanpasu-state 采用类似 TCC 的控制反转型状态事务:配置 actor 只负责构造候选值,由状态层编排 prepare、持久化、CAS commit 和通知。对当前运行有影响的参与者(运行中的配置、切换内核、切换服务模式等)通过 Try / Confirm / Cancel 参与同一笔事务:Try 失败时源配置不提交,持久化失败时 Cancel 恢复原状态。托盘、界面、系统代理等外围效果在提交之后再协调,其失败会单独显示为“已提交但未收敛”,不会被当作“配置未保存”。
内核管理(nyanpasu-runtime)
CoreControl 统一了本地模式和服务模式的语义:校验、revision CAS、分类、执行、验证、回退和发布在同一个 Reconcile 事务中完成;操作经有界串行队列执行,并以 OperationId 保证幂等。调用方断开或放弃等待不会中断已开始的操作。服务端承载的是同一套完整的 CoreControl,不是简化版后端。
CoreActor 只负责选择本地或服务端点、转发操作和投影状态,不再保存第二份生命周期状态;ServiceActor 负责服务的安装、版本兼容、探活、重连与卸载。本地与服务之间的切换是显式的控制权交接,带 generation 防护。
CoreErrorKind 结构化返回,状态以完整快照推送,事件流丢失(Lagged)后自动重新同步;配置以内容和摘要传输,不再传递服务端本地路径。Windows 内核命名管道增加访问授权,服务日志不记录环境变量的值。
统一 RPC
#[nyanpasu_macro::rpc] 声明,Tauri IPC 和可选的本地 HTTP 服务共用同一个应用层;前端类型由 Specta 生成,前端只通过 @nyanpasu/rpc 和 @nyanpasu/query 调用后端。
新的基础组件
nyanpasu-tsdb:为流量分析编写的列式时序数据层。数据按时间分桶,标签以字典编码,按列分块存储;查询基于快照;保留期清理、合并与空间回收在后台维护任务中完成;所有按数据量分配的内存都计入内存预算,以 redb 作为持久化后端。
nyanpasu-local-channel:父子进程之间的类型化本地双向通道,带访问令牌、类型指纹校验、帧大小上限和平台 ACL。独立 widget 通过它与主程序通信。
前端工程
storage.db(redb)中的 KV 存储,前端通过 useKvStorage 读写,用法类似 useState:同一窗口内同一个键只读取一次后端,此后由变更事件保持最新;写入会立即反映到所有使用该键的组件,并按调用顺序提交;每次读、写和变更事件都带 revision,事件积压后会触发重新同步。localStorage 只作为首帧缓存。这些状态因此在多个窗口和 HTTP 客户端之间共享,也会随配置备份一起保存。
开发与验证
lint:architecture-ledger 禁止新增全局服务单例,进程级 static 必须登记用途;lint:backend-boundaries 检查后端 crate 的依赖方向(中立 crate 不得依赖 Tauri、egui 或 Slint);lint:frontend-boundaries 检查前端包之间的依赖方向。
deno task bench:ab 在两个提交之间交替运行 A/B 对比。后端提供 trace-chrome 和 dhat-heap 两个 profiling feature。
clash_api_get_providers_proxies 只返回 Provider 摘要(含 proxyCount),不再返回完整节点列表、testUrl 和 expectedStatus(#5831)。
docs/development/:架构与所有权、统一 RPC、测试与评审、工作流、Rust 与 TypeScript 代码风格、前端包、仓库脚本。
性能
场景
测试条件
改动前 → 改动后
Windows 主窗口
不再以透明窗口创建,3840×2064 窗口
窗口打开时少一块约 30 MB 的重绘位图(随窗口尺寸变化)
独立 widget(Windows)
release 构建,从应用子命令启动
工作集约 150 → 24 MiB;线程约 32 → 3
独立 widget(macOS)
Apple M3,2x 缩放,1 次/秒更新,软件渲染对比 femtovg
内存占用(footprint)约 77 → 16 MiB
enable-loopback
v0.1.4,只构建可见区域的行
启动私有工作集约 107 → 71 MiB
运行时配置快照
Windows,DHAT,同一配置,窗口打开 90 秒
Rust 堆(结束时)10.99 → 8.23 MiB;快照部分 3.63 → 0.61 MiB
Windows 后台内存
主窗口关闭,1 小时合成代理负载,启用 Segment Heap
私有字节 43 → 32 MiB
流量报表查询
500,000 行小时数据,完整报表
约 72 → 9 ms(相对初版 tsdb 实现);单次请求分配 21.8 → 0.77 MiB
连接页
Chromium,4x CPU 降速,6,000 条连接按下载速度排序
采样最长帧 50–67 → 17–33 ms;打开时最长任务 301–375 → 108–113 ms
切换代理组
30 组 × 1,500 节点,Chromium,4x CPU 降速
最长帧 73 → 27 ms
Profile Inspect
WebView2,应用内中位数
打开 181 → 43 ms;Output 标签 175 → 15 ms
大型 diff
1,500 个 hunk,Chromium
最长任务 327–422 ms → 无超过 50 ms 的任务;高亮 1.6–2.1 s → 约 0.1 s
打开大型本地 Profile
大 YAML 文件
主线程脚本耗时 843 → 319 ms(YAML 解析移入 worker)
连接数据解码
每帧 150 条连接
请求的分配字节减少约 47%–55%
重要修复
port 与 Nyanpasu 的 mixed-port 相同时,内核在冷启动时可能先占用 HTTP 端口,导致混合端口监听失败、仪表盘误报“端口被其他程序占用”(#5720)。
ipv6,而 clash-rs 实际读取该字段(#6019)。
allow-lan 等设置在重启后丢失;托盘中同一代理组出现多个选中项;仪表盘在窗口隐藏后冻结。
依赖与工具链
致谢