The secondary wait only polled the notify endpoint, which a restarting instance has already shut down before spawning its successor, so a child that lost the spawn-vs-exit race could never acquire the freed lock and died after 20s behind a startup-failure dialog. Retry try_lock_instance on every poll so the child promotes as soon as the old process exits. Double-launch handoff and wedged-holder timeout behavior are unchanged.
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.
Every settings toggle reparsed the profile and chain files, ran four
Boa interpreters, serialized the runtime config twice, and re-ran
mihomo -t over bytes the core had just accepted. Builtin and template
scripts now run without Boa, custom scripts bind the config through
JSON.parse and take ownership instead of per-script clones, the config
serializes once, and mihomo -t is skipped unless the bytes, core
build, or geo assets changed. Heavy parses and serializations moved
to spawn_blocking. Large-subscription toggles drop from hundreds of
milliseconds to ~140ms with no new retained state.
* 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>
* feat(service): hand upgraded cores to the service through the installer
The service now only executes administrator-staged core copies, so an
in-app core upgrade has to deliver the new bytes there before the
restart asks for them; otherwise a service-mode restart keeps running
the previous core while the UI reports the new version.
After publishing the downloaded core, service-mode upgrades invoke the
elevated service installer with --install-core <path> --sha256 <hex>.
The digest is computed over the published file and rides the elevated
command line, which no other local account can alter, so a file
swapped after hashing is refused rather than staged. Sidecar-mode
upgrades run the file directly and prompt for nothing.
Rollback distinguishes staging that never ran, was refused, or
succeeded: only a successful staging obliges the rollback to restore
the approved copy too (deliberately not gated on the running mode,
which reads NotRunning after the very crash being rolled back), and a
refused staging restores the file so a retry does not see the new
version on disk and conclude there is nothing to do.
Requires clash-verge-service-ipc >= 2.6.7. The pinned dependency and
the packaged service release must move together with this change, or
the old installer silently treats --install-core as a plain install.
* feat(installer): attest bundled cores to the service at install time
prebuild computes sha256 digests of the downloaded mihomo sidecars
into packages/windows/core-hashes.nsh (gitignored), included through
the NSIS installerHooks path. After unpacking and before starting the
service, the installer stages both cores into the service's approved
directory with those digests, so what gets attested is exactly what
this installer shipped: a core swapped on disk in a user-writable
install directory is refused, not published. Failure is logged and
does not abort the install; a later elevated service install can
stage the cores again.
* chore(deps): require clash-verge-service-ipc v2.6.8
v2.6.8 is the first service whose installer understands
--install-core --sha256; the staging this branch introduces is inert
against anything older, because the old installer treats the flag as a
plain service installation and reports success. The service release and
this pin therefore have to ship in the same app release.
* fix(service): heap-allocate the core hashing buffer
clippy::large_stack_arrays denies the 64 KiB stack array.
Two months of usage data (56 evaluated runs, 1372 AI credits) show a
median of 22 credits and 6 tool turns per review, with 97% of billed
context being cache tokens anchored on the prompt itself.
Cap each run at 12 turns and 60 credits so only runaway sessions are
stopped, and stop triggering on reopened, which carries no new
implementation evidence; workflow_dispatch remains available for
manual re-reviews.
Compact the policy body from 367 to 177 lines by merging the signal
lists with the weighting/escalation sections that repeated them, with
no verdict, label, rerun-stability, or output-contract semantics
dropped. Add a tool-call budget for normal evaluations and a fast path
for fork-sync and placeholder PRs, which were 29% of measured
credits.
Codify the rules agents and contributors are judged by: a tracked
AGENTS.md instruction contract, a Contribution Expectations section in
CONTRIBUTING, and a minimal PR template. Align the AI-slop review
policy with them - linkage substance, test/defensive-code padding,
write-access skips, disclosure as transparency - and add two
tamper-resistant checks: an ai-slop:high merge gate with a linked-issue
requirement (no-issue-needed exemption), plus a docs-consistency anchor
check guarding the cross-references.
* refactor(log): migrate logging to tracing-estuary pipeline
Swap flexi_logger + clash-verge-logger wiring for the tracing-estuary
crate: buffered file sink with explicit panic/exit drains, live level
switching, and tokio-trace/chrome-trace behind crate features.
AsyncLogger moves in-house (VecDeque ring); file format and rotation
stay unchanged.
* fix(log): reset sidecar writer in place and re-pin service-ipc v2.6.7
Rebuilding the sidecar FileLogWriter on config changes leaked flexi's
unstoppable flusher thread plus an fd each time; the writer is now flushed
and reset in place, matching what the service crate does.
get_clash_logs_by_service drops the CompactString conversion layer now that
service-ipc v2.6.7 returns plain Vec<String>, and AsyncLogger is renamed
LogRing to match.
* refactor(log): span-based observability and log noise cleanup
Instrument spans carry the structure flat lines never could: the core-start
spine (mode, readiness/owner generations, pid, config file), proxy apply and
clear routes with guard generations, service IPC sessions with refusal codes
and outcomes, profile-switch terminal outcomes, subscription fetch strategies,
core upgrades with per-proxy version probes, backup flows, timer tasks, config
generation uids, and the startup setup flow; running-mode changes emit one
guarded transition event each.
~90 hand-written noise lines are gone or demoted (entry+success pairs, polled
getter echoes, phase brackets, window sub-steps, platform install chatter);
errors keep their anyhow chain, operation name, and item id, and swallowed
retry results surface per attempt.
pnpm 12.3.4 deterministically breaks every Windows CI build: the install inside the tauri beforeBuildCommand fails importing into the pnpm store with os error 32 (ERROR_SHARING_VIOLATION). Reproduced on fresh runners with caches wiped; 12.3.3 was green on the same pipeline. Re-pin to 12.3.3 until upstream ships a fix.
Locks both sides to upstream main 17c7757: the WS channel now uses a
single Json transport (connections wire shrinks ~3.4x) and count-stream
error frames are forwarded unchanged; JS/Rust API surfaces stay
identical, so upper-layer code is untouched except the card below.
The home Active Connections card now subscribes to the count-only
ws_connections_count stream instead of parsing the full connections
snapshot every second; the full stream runs only while the Connections
page is mounted.
Drive the production home traffic graph through embedded WebDriver in an
isolated optimized measurement build. Record attributed WebContent and main
process CPU/RSS distributions across foreground, hidden and restored phases.
Keep replay, raw reports, independent-run comparison, cleanup checks and
focused validation available through project commands. Normal release builds
exclude the automation service and measurement entry points.
Consolidate ordinary query snapshots on SWR and make Profiles own its query key, cache mutation, and invalidation policy.
Impact:
- remove the generic synchronous query Map while keeping dedicated Mihomo WebSocket snapshots
- eliminate duplicate Profiles refreshes while preserving retries and the 800 ms event throttle
- preserve preload-backed Verge updates and system proxy rollback behavior
- scope uptime polling to the Home Clash info card instead of the app lifetime
- leave RunState, Connections, Traffic, backend, and IPC contracts unchanged
- reduce frontend code by 72 net lines without adding dependencies
- Remove hardcoded body font-family from index.scss, use MUI theme dt.font_family instead
- Extract monospace font stack to shared MONACO_FONT_FAMILY constant in utils/font-family.ts
- Add platform check for twemoji mozilla in ip-info-card.tsx
- Consolidate 5 Monaco Editor font-family declarations into single constant
* fix(clippy): Remove 2 unused imports
- Drop 2 unused imports according to clippy suggestions
* fix(clippy): Re-add 2 imports and limit to macOS
- Those "unused imports" are only for Windows and Linux
- macOS environment requires those identifiers
* refactor: remove duplicated list wrapper in side menu
* refactor: simplify side menu layout and drag drop logic
- Always render DragDropProvider and pass disabled prop to menu items
- Remove redundant layout branches and unused sortable component
* ci(workflows): Revert nodejs version to v24.18.1
- Exactly match what was defined in `.tool-versions`
* ci(renovate): Prevent 3 build tools from being automatically upgraded
- Lock Nodejs, PNPM and Rust version in the repository
- Nodejs, PNPM and Rust are infrastructure build tools or package manager for this repo
- Human manual-bump is required for consistency and stability
- Prevent bumping by Renovate Bot
* ci(renovate): Unlock auto updates of 3 build tools
- Re-allow Nodejs, PNPM and Rust from being automatically upgrade
- Group version bumps together across version lockfiles, GitHub Workflows and Dev Containers
Assisted-by: vscode-copilot-chat:gemini-3.7-flash codegraph
* chore(deps): Bump 2 build tools to latest version
- Bump Nodejs to `v24.20.0` across version lockfiles, GitHub Workflows and Dev Containers
- Bump Rust toolchain to `v1.98.0` across version lockfiles, GitHub Workflows and Dev Containers
Assisted-by: vscode-copilot-chat:gemini-3.7-flash codegraph
The switch read enable_tun_mode while the Core was given
enable_tun_mode && !session_suppression, so falling back to Sidecar left it
showing a TUN that was not running, with nothing to write the flag back.
Drop the session flag: the stored preference is the only truth, re-checked
at startup and written off when the conditions for it are not met, and the
switch renders it against current capability.