The v2.5.4 notes had grown to 97 free-form entries exposed verbatim in
the in-app update dialog. Distill them to 58 one-theme-per-line entries
capped at ~60 CJK characters with no internal terminology, and move the
writing rules into template/Changelog.md so every cycle starts from them.
Release plumbing now agrees on the --- divider: extract_update_logs.sh
stops there like updatelog.mjs, so file-only content never reaches
release bodies, while updater.mjs appends a per-tag See More link to the
update notes it generates. scripts-workflow/group_platforms.sh locks
platform entries under emoji platform headings, wired into pre-commit,
release and autobuild CI, and the changelog bump script; AGENTS.md points
agents at the template rules.
* fix(ui): use utf-8 encoding for inline SVG icons to support non-latin characters
* chore(test-item): re-add data-sortable-handle to TestItem box
* docs: update changelog
* fix(macos): discard a core cache the current user cannot write
* docs(changelog): add the unwritable core cache fix
* docs: update changelog to include Linux in cache.db ownership fix
---------
Co-authored-by: oomeow <oomeow@outlook.com>
* fix(sysproxy): gsettings command is no longer mandatory on KDE desktop
* chore(tauri): update sysproxy dependency to use main branch
* chore(deps): update clash_verge_service_ipc to v2.6.6
* docs(changelog): add KDE proxy setting support note
* refactor: migrate to @dnd-kit/react and simplify sortable components
* chore: enable css formatting in biome.json
* refactor(profile): simplify icon rendering logic and add alt text
* style(profiles): add overflow hidden to profile grid container
* refactor(profile): add radix for parseInt and improve type safety in profiles
* docs: update changelog with drag-and-drop styling improvements
* refactor(profile): move hasValidName function out of ProxiesEditorViewer
* refactor(proxy): refactor proxy chain into sortable components
* feat(proxy): add drop state styling and arrow animations to proxy chain
* style(profiles): reduce horizontal padding in profile grid
* feat(profile): add vertical margin to editor viewer items
* chore: refresh pnpm lockfile
* fix: preserve drag and drop behavior
---------
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
* fix: Gemini test
* naming unlock
* test type
* refactor: deduplicate media unlock checks
* fix: run media unlock checks individually
* fix(media-unlock): satisfy clippy const lint
* fix: stream media unlock test results
* fix: streamline media unlock checks
* fix: force HTTP/1 for media unlock checks
* fix: limit concurrent media unlock checks
* feat: allow concurrent media unlock item checks
The startup fallback persisted its replacement, so a port blocked once was never
asked for again. It now overrides the Runtime Config for the session only.
Most of those conflicts were not real: SO_REUSEADDR cannot reuse a TIME_WAIT
socket owned by another user, and a service-managed core runs as root while the
app does not. A refused bind is now confirmed by asking whether anything answers.
Also restores the borrowed port when saving proxy ports fails.
* fix(cmd): preserve anyhow context in coded errors
Use alternate error formatting so coded failures retain the full anyhow context chain without changing their wire format.
* fix(macos): skip redundant proxy disable writes
When both proxy modes are off, read macOS state first and skip networksetup if the OS is already clean. Update the guard target only after a successful write.
* feat(proxy): classify system proxy failures
Attach stable, actionable proxy failure codes to anyhow chains while preserving the original diagnostic causes.
* feat(cmd): return structured command failures
Replace encoded error strings with serializable code and detail fields, and update frontend notice consumers to handle the structured shape.
* fix(scripts): use the js-yaml namespace import
Import js-yaml through its ESM namespace so the i18n cleanup script can access load and dump.
* feat(proxy): localize classified proxy failures
Map privilege and direct-fallback codes to localized explanations, and let mapped causes outrank generic operation keys in notices.
* fix(ui): bound notice text and render failure details
Limit resolved notice text without truncating clipboard content, and normalize structured failures embedded in translation parameters.
* feat(proxy): persist unseen proxy failures
Store unresolved classified failures by code, notify the frontend when the table changes, and show each failure sequence once when a visible window can receive it.
* feat(proxy): report tray and hotkey toggle failures
Record classified failures from tray and hotkey proxy toggles so they appear when a visible window is available.
* fix(ui): restore the proxy switch after failed toggles
Refresh frontend proxy state after a failed toggle so the switch reflects the rolled-back configuration.
* feat(proxy): stop the guard after repeated failures
Report guard outcomes, stop after the failure threshold, and persist the classified failure for the frontend.
* fix(macos): preserve proxy during service handoff
Stop a sidecar being handed to the service without clearing proxy state that the new owner must inherit.
* feat(macos): classify misplaced sidecar state
Distinguish a refused sidecar proxy write from a machine that still needs the privileged service installed.
* feat(ui): recover misplaced sidecar notices
Offer a restart action for macOS proxy failures caused by a ready service while the core still runs as a sidecar.
* feat(ui): install the service from proxy notices
Let privilege notices install the macOS service, restart the core, and report the runtime mode that was actually reached.
* feat(cmd): attach requested proxy operations
Carry the requested proxy direction with structured command failures when the originating command knows it.
* feat(sysproxy): drain guards before OS access
Wait for the local proxy guard to stop before OS reads, service handoff, or final writes, and refuse transitions when it does not drain.
* feat(sysproxy): recover partial proxy writes
Use write progress to choose whether to restore the old guard or compensate with a disabled proxy state, while preserving actionable errors.
* feat(sysproxy): skip already-applied proxy writes
Compare macOS proxy snapshots with global, PAC, and disabled targets so matching state avoids redundant privileged writes.
* feat(proxy): report background proxy failures
Persist and surface classified proxy failures from lifecycle paths that have no direct caller awaiting the result.
* feat(ui): move proxy recovery into a dialog
Guide users through installing or switching to the service after a refused proxy write, and suppress duplicate toast reports.
* fix(ui): close proxy dialog after service recovery
Dismiss the recovery dialog once the core reaches service mode, even when the original proxy request remains pending.
* feat(ui): retry proxy request after service recovery
Replay the requested proxy direction after the core reaches service mode, while leaving incidental restores unchanged.
* fix(proxy): refresh state after successful apply
Publish the proxy refresh from the shared apply path after releasing the lifecycle lock, and remove the tray-specific duplicate.
* feat(ui): show proxy recovery progress
Display installation, restart, and proxy-apply stages while keeping the primary action spinner visible during recovery.
* feat(ui): route unavailable TUN through service recovery
Let the TUN switch request service recovery and restore its requested state after the core restarts in service mode.
* fix(ui): avoid duplicate TUN recovery errors
Roll back deferred TUN toggles without reporting an error, and publish configuration refreshes from the transaction commit path.
* chore: update changelog & pinlock
* fix(core): resolve platform-specific clippy warnings
* fix(core): detect Windows wildcard TCP conflicts
Windows permits a specific exclusive bind beside an existing non-exclusive wildcard listener. Consult the system TCP listener table so the probe reports that overlap as a conflict.
* feat(layout): add logging of MihomoWebSocket instances in dev mode
* refactor(hooks): defer ws assignment in use-mihomo-ws-subscription
* chore: update tauri-plugin-mihomo-api dependency source to use github protocol
* docs: update changelog with websocket connection fix
* feat(service): isolate macOS launch and owner runtime
* ci(windows): run owner security tests
* chore(deps): use kode-bridge v0.4.1 tag
* fix(macos): classify installed service state
* fix(macos): classify marked unavailable service
* fix(macos): gate core startup on service migration
* fix(macos): scope service init to supported platforms
* feat(macos): prompt before migrating installed service
* fix(macos): shorten sidecar IPC path
* build(service): pin helper protocol and artifacts
* fix(core): require confirmed service and sidecar readiness
* fix(macos): harden launch roots and singleton state
* fix(ui): refresh migration state before restart
* fix(macos): linearize service migration lifecycle
* fix(ui): keep service migration state fresh
* feat(service): track authenticated owner sessions
* fix(service): preserve newer owner sessions
* feat(macos): route service proxy changes through helper
* fix(macos): serialize service proxy guard
* fix(macos): close service proxy owner lifecycle
* fix(macos): close remaining proxy stop races
* fix(app): do not cancel controlled service stop
* fix(lifecycle): keep controlled updates cancellation-safe
* fix(macos): stage dev core for service
* test(macos): exercise staged core cleanup
* fix(dev): await controlled macOS exit
* chore: update changelog
* fix(macos): recover sidecar after service install failure
Allow the existing sidecar to continue when service installation leaves the manager in InstallRequired, then settle the session state as SidecarAllowed. Show neutral status text while the migration dialog waits for its final state.
* fix(macos): stage dev service tools before elevation
* fix(macos): localize launch guard prompts
* fix(service): address cross-platform integration issues
* feat: support seamless service migration
* fix: pass Windows service installer path safely
* fix(prebuild): derive service release from Cargo dependency
* fix(dev): preserve service installation state
* fix: resolve clippy warnings in service lifecycle
* fix(connections): show destination IP as host for raw-IP targets
When metadata.host is empty (a raw-IP CONNECT with no domain), the
connection "Host" column fell back to remoteDestination (the outbounds
relay/exit address) joined with the destination port, which misleadingly
showed the relay as the connections destination.
Fall back to metadata.destinationIP instead, in both the list column
(getConnectionHost) and the detail panel.
Closes#6669
* fix(connections): preserve fallback for empty destination IP
---------
Co-authored-by: wonfen <eiwonfen@gmail.com>
* feat(proxy): implement sticky virtual list and group tools
- Add new StickyVirtualList component for better performance with sticky headers
- Create ProxyGroupTools component for filtering, sorting and testing proxy groups
- Enhance proxy groups with improved scrolling and group toggle functionality
- Integrate search box with click event handling
- Remove redundant ProxyHead component usage
* style: remove unused import and update TypeScript types
* refactor: convert function component to forwardRef component to fix biome lint error
* feat(proxy): extract proxy chain UI to separate component
* refactor: remove custom throttle implementation and simplify dependencies
* feat(proxy): improve proxy groups UI and scrolling behavior
- Add initialOffset prop to StickyVirtualList for better scroll position restoration
- Refactor ProxyGroups component to separate chain and normal modes
- Implement scroll position persistence for both chain and normal modes
- Add sticky shadow effect for expanded proxy groups
- Remove unnecessary ScrollTopButton component
- Optimize scroll event handling with throttling
- Improve code organization with custom hooks and component separation
* docs(proxy-groups): Add TODO comment for initial render position issue
* feat(proxy): improve scroll position handling and UI display
* refactor(proxy): simplify scroll handling logic and remove unused code
* fix(sticky-virtual-list): remove duplicate styles and add padding
* refactor(proxy): rename scroll offset variables and functions for clarity
* refactor: remove unnecessary refs and simplify onClick handlers
* fix(proxy-groups): handle initial scroll position state
* feat(zed): add biome formatter configuration
* refactor(proxy): remove unused headState import and type annotations
* style(proxy): improve type imports and conditional rendering
* .
* feat(proxy): add ProxyHead component to render in global mode
* chore: ignore .zed directory
* docs: update changelog
Wait longer for slow Windows service startup, then hand off from sidecar
to service when it becomes ready. Retry service core startup during the
handoff window, and clean up root-owned macOS service core/IPC leftovers
before uninstalling the service.
* fix: replace toSorted with slice().sort() for macOS 12 compatibility
Array.prototype.toSorted() is ES2023 and not supported in WebKit < 16
(bundled with macOS 12 Monterey). Using slice().sort() is functionally
identical and works on all platforms.
Fixes#7216
* chore: update Changelog
---------
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
* fix(connections): stabilize table memory usage
Render the connections table and list from stable row view models, and replace the TanStack row/cell instantiation path with a lightweight virtualized table body.
The leak was isolated to the frontend table render path: websocket data without the table stayed flat, while the normal table path kept producing large per-snapshot object graphs under active/closed churn.
Introduced-by: bf06cbc87d (introduced the TanStack table path)
Related-hot-path: 068678135 (made default ordering/filtering hot enough for long-running /connections sessions to amplify retained heap/RSS)
Related-retention-path: 7fc238c27b (moved Home stats to the full connection websocket subscription, so Home could keep connection snapshots alive for totals/count)
Keep UI behavior intact: column visibility, column order, resizing, sorting, connection details, the closed-connection cap, and the 500ms refresh cadence remain.
* fix(connections): lazily release connection snapshots
Keep the full active/closed connection snapshot scoped to /connections by using a short React Query gcTime for the full subscription.
Home now subscribes to a lightweight connection summary for totals and active count, so leaving /connections no longer keeps the full active/closed arrays and closed history alive for the dashboard.
Only the selected Active or Closed mode feeds filtering, sorting, row-view derivation, and table/list rendering. Switching modes remounts the row subtree and closes detail/column-manager state without changing the capped closed-history behavior.
* fix(connections): decouple collection from rendering
Move the high-frequency connection websocket path out of React Query and into a module-level external store consumed with useSyncExternalStore.
The store keeps one normalized active snapshot plus the capped closed history, continues collecting across route changes, and only notifies mounted subscribers. Home reads the same store through a lightweight summary snapshot, so leaving /connections no longer renders the table/list while connection history is still preserved.
This replaces the short-gc release behavior that made Active/Closed history disappear after navigating away, and bounds retained data to current active connections plus the closed cap instead of React Query cache objects.
* fix(connections): keep collection store authoritative
Remove the temporary per-subscription gcTime override added for /connections. The connection monitor now owns active/closed retention outside React Query, so route changes should stop rendering without clearing collected history.
This leaves the shared Mihomo websocket hook on its original 30s cache behavior for logs, traffic, and memory while /connections uses the external store introduced in the previous commit.
* perf(connections): coalesce snapshots before parsing
Keep only the latest raw websocket message during the 500ms throttle window and parse it when the store flushes. High-churn connection bursts no longer allocate parsed object graphs for snapshots that will be overwritten before React can observe them.
Also compare incoming metadata through the same normalization used for retained records, so optional undefined fields do not prevent metadata reference reuse.
* perf(connections): trim render allocations
Reuse existing row view objects before formatting derived strings when the retained connection object reference is unchanged. Stable closed-history rows no longer allocate throwaway display strings on every snapshot.
Measure the table scroll viewport on mount and resize instead of assuming a 1200px body, so virtual rendering starts from the real visible row count. Keep table state across Active/Closed switches and share the relative-time cell between table and list rows.
* perf(connections): tighten shared time updates
Refresh the shared relative-time clock before the first subscriber render and switch the listener registry back to a Set, avoiding stale labels after returning to /connections and keeping subscriber churn O(1).
Also sort table time rows by the existing numeric startTime field, drop the redundant row-view startTime equality check, and remove one unnecessary table prop guard.
* perf(connections): skip table-wide row projection
Stop materializing ConnectionRowView objects for the whole filtered dataset in table layout. The page now keeps raw connection records for the table path and only formats visible cells inside the virtualized table body, while list layout keeps the cached row-view path.
This removes the steady 500ms allocation pass that was still walking every filtered connection before table rendering. Detail lookup now reads the current filtered raw record directly, and the table clamps scroll state when switching between datasets of different lengths.
* perf(connections): skip unnecessary filter clone when table not searching
In table mode, avoid creating a filtered copy when search is empty: only apply search/sort work for non-empty query while retaining the same default order behavior. Also replace parsing in order comparators with numeric startTime to avoid per-tick Date object churn and use SearchBox state to detect an empty search.
In table layout without search input, use upstream connection snapshot directly for rendering instead of cloning/sorting every interval tick. This removes a persistent per-update array allocation path while keeping list-mode sort/search behavior unchanged.
* perf(connections): bound closed merge without full transient arrays
Cap closed-history promotion while iterating previous active set without building a temporary large closed array. This preserves the 500-item limit while avoiding 100k-scale transient allocations when many connections close between snapshots.
* fix(changelog): address memory leak caused by frontend
* perf(connections): cache visible table cell snapshots
Add a bounded row snapshot cache for the virtualized table so repeated paints and optional column sorting reuse stable formatted strings instead of rebuilding host/source/rule/chains/traffic text on every refresh. The cache is capped to avoid retaining large active sets.
Also skip full connection-data snapshot merging when only summary listeners are mounted, keeping Home on the summary-only path without changing Connections history while the page is subscribed.
* chore: update Changelog
* chore: update Changelog