Commit Graph
4614 Commits
Author SHA1 Message Date
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 3df3ef89ee chore(deps): update rust crate async-trait to 0.1.92 (#7703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 15:21:45 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 8cddcd6445 chore(deps): update dependency knip to v6.32.0 (#7694)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 11:29:14 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> dd56c7374d chore(deps): update github/gh-aw-actions action to v0.86.1 (#7699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 01:34:23 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 9a6adb887d chore(deps): update rust crate flexi_logger to 0.31.10 (#7698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 01:34:20 +00:00
Tunglies 6d9813756d style: fix side menu fontWeight
Ref: #6578
Close: #7536
2026-08-08 02:32:28 +08:00
Tunglies 1ebe2ab0f8 chore: update pr-ai-slop-review 2026-08-08 01:32:57 +08:00
Tunglies 19744805a9 chore: remove unused config 2026-08-08 01:22:06 +08:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 2f44d2bc7d chore(deps): update github/gh-aw-actions action to v0.86.0 (#7695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-07 06:23:30 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> a3ccd59c34 chore(deps): update github/gh-aw-actions action to v0.85.4 (#7693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 10:13:46 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> b138eb848d chore(deps): update rust crate open to 5.4.1 (#7690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 00:24:04 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> dadf53c46a chore(deps): update github/gh-aw-actions action to v0.85.1 (#7689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 00:14:46 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 85eb3931b9 chore(deps): update github/gh-aw-actions action to v0.85.0 (#7686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-05 01:26:08 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> c4268f7918 chore(deps): update github/gh-aw-actions action to v0.84.4 (#7685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-05 00:09:03 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 0b3d00b77d chore(deps): update github actions (#7676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-04 21:28:47 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 859afee337 chore(deps): update rust crate base64 to 0.23.1 (#7680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-04 21:27:26 +00:00
queukat e7b1807fef Improve Russian localization (#7138) 2026-08-04 13:20:27 +00:00
Tunglies a8275b20b7 refactor: extract media unlock checker crate 2026-08-04 11:37:54 +08:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 544c47c634 chore(deps): update github/gh-aw-actions action to v0.84.3 (#7675)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 11:58:23 +00:00
Tunglies c5b641e421 fix: make profile deletion rollback-safe 2026-08-03 20:00:01 +08:00
903410c12e chore: align local Nodejs version with CI (v24.18.1) (#7339)
- Bumps the required Node.js runtime version to 24.18.1 in the tool configuration.

Assisted-by: Gemini_CLI:auto-gemini-3.5 codegraph

Co-authored-by: chengww <chengwang@xiaomi.com>
Co-authored-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2026-08-02 16:54:46 +00:00
Tunglies 1599ca0e09 fix: add context to file-not-found errors (#7665) 2026-08-02 00:39:10 +00:00
renovate[bot]renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Tunglies
837752a768 chore(deps): update npm dependencies (#7607)
* chore(deps): update npm dependencies

* fix(monaco): support editor 0.56 worker exports

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
2026-08-01 17:12:04 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> d60ded5b3f chore(deps): update rust crate rustls to 0.23.43 (#7629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 16:50:53 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> e9b2c013b6 chore(deps): update github actions (#7632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 16:50:52 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> c7c2efe54f chore(deps): lock file maintenance (#7653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 16:50:50 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 248b63dbbd chore(deps): lock file maintenance (#7654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 16:50:39 +00:00
oomeow 49257a026c fix: app freeze when emit refresh proxy config event (#7662) 2026-08-01 15:19:26 +00:00
oomeow 8ef6f0cc23 chore: update tauri-plugin-mihomo deps (#7647)
* chore: update tauri-plugin-mihomo deps

* clippy
2026-07-31 14:02:20 +00:00
7d8f98e183 fix(macos): keep DNS state outside app bundle (#7544)
* fix(macos): keep DNS state outside app bundle

* fix(macos): restore legacy DNS state

---------

Co-authored-by: Arcanum <260421450+ArcanePivot@users.noreply.github.com>
Co-authored-by: wonfen <eiwonfen@gmail.com>
2026-07-31 09:44:56 +08:00
ef179fcf61 fix(home): manual update check not working when auto_check_update disabled (#7585)
* fix(config): prevent cleanup_orphaned_files from deleting active profiles

When IProfiles::new() fails to parse profiles.yaml (e.g., corrupt file), it
returns Self::default() with items: None. The subsequent
cleanup_orphaned_files() call then sees no active files and deletes all
profile files in the profiles/ directory except the two hardcoded protected
files (Merge.yaml and Script.js).

Guard cleanup_orphaned_files() against this by checking if items is None
or empty before proceeding. When items is unavailable, skip the cleanup
and log a warning instead of blindly deleting user data.

Fixes #7577

* fix(home): manual update check not working when auto_check_update disabled

When auto_check_update is false, useUpdate() sets enabled=false for the
SWR query, which sets the SWR key to null. Calling swr.mutate() on a null
key does not execute the queryFn, returning undefined instead.

This caused the home page's "last check time" click to instantly show
"already up to date" without actually checking for updates.

Fix: use revalidateQuery() for the manual checkUpdate function, which
uses the global SWR mutate with the actual query key, bypassing the
enabled: false state and always triggering a real network request.

Fixes #7584

* fix: preserve manual update and profile data

---------

Co-authored-by: Evan Gong <evan@users.noreply.github.com>
Co-authored-by: wonfen <96291150+wonfen@users.noreply.github.com>
Co-authored-by: wonfen <eiwonfen@gmail.com>
2026-07-31 06:52:10 +08:00
oomeow 4b3bc54b2d fix(ws): assign websocket after onConnected succeeds (#7639)
* 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
2026-07-30 15:33:45 +00:00
oomeow 10dbe60671 fix(proxy): fix inline providers being filtered after Mihomo API change (#7640)
* feat(proxy): add Inline vehicle type support

* docs: add fix for Mihomo API proxy-provider filtering to changelog
2026-07-30 14:49:38 +00:00
oomeow 07a1515d8c feat(logging): introduce ModuleFilter with exclusion support and logging tauri_plugin_mihomo (#7637)
* feat(logging): introduce ModuleFilter with exclusion support

* refactor(logging): simplify exclude check using if-let chain
2026-07-30 12:48:22 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 5cbb0b6cfd chore(deps): update github/gh-aw-actions action to v0.84.0 (#7630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-30 04:00:58 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 3de4d53b8f chore(deps): update github/gh-aw-actions action to v0.83.5 (#7627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-29 15:04:20 +00:00
oomeow f69d03c4d4 refactor(dns-viewer): use matchAll for name server policy parsing (#7626)
* refactor(dns-viewer): use matchAll for name server policy parsing

* chore: biome lint

* chore(biome): disable noExplicitAny rule in linter settings
2026-07-29 12:37:57 +00:00
wonfen b98c9be7db fix: keep current proxy menus interactive 2026-07-29 15:36:07 +08:00
wonfen 7e0cf4f9f6 fix: remove invalid platform reference from macOS dev anchor 2026-07-29 14:15:01 +08:00
wonfen 98d70978e4 fix(service): keep health probes and sidecar fallback consistent 2026-07-29 12:39:24 +08:00
StarsSail 7fb5001bea fix: enable shell option for child_process.spawn on Windows (#7619)
* fix: enable shell option for Windows in runDevCommand

* fix: enable shell option for Windows in runDevAnchor
2026-07-29 03:52:48 +00:00
wonfen 593ac07f03 fix(service): restore sidecar fallback after failed actions 2026-07-29 11:22:10 +08:00
oomeow 382cbf9fb5 fix(dns-viewer): parse empty to yaml error (#7616)
* feat(dns-viewer): initialize yamlContent with empty object string

* feat(dns-viewer): prevent overwriting user config with initial YAML values

* fix(dns-viewer): add null check for parsed yaml object
2026-07-29 00:53:38 +00:00
wonfen 3d8d7731e1 fix: node selection persistence (#7620)
* fix(core): put the user's node choices back when the core starts

mihomo restores the node picked in each group from the `cache.db` it keeps
in the directory it was started against. The app relied on that entirely,
and it does not hold: `profile.store-selected` comes from a merge template
a user is free to replace, and a service older than the durable runtime
generation starts every core in a directory nothing has ever run in. Both
end the same way — every `select` group falls back to the first entry in
its `proxies:` list.

The app already knows better. It records each selection in the profile,
and `activate_selected_nodes` already reconciles that record against the
running core — it was only ever called when switching profiles, never when
a core came up. Call it from the three places a core process becomes
ready. Repeat calls supersede each other, so no coordination is needed
between the start paths.

That makes the profile authoritative, which turns any selection it does
not know about into one the next start silently undoes. The chain proxy
moved a group without recording it, so recording is now one shared hook
that both it and the proxy list go through.

Restoration is spawned, not awaited: it polls the core until its groups
are readable, and a start must not wait for that.

* fix(tray): record the node the tray switched to

Restoring the profile's selections when a core starts made the profile
authoritative, which turns any selection it never learned about into one
the next start silently undoes. The proxy list and the chain proxy both
record; the tray did not.

So switching node from the tray survived only until the next restart, and
then reverted to whatever the profile last knew — a regression the
restoration itself introduced, and only for the tray.

`record_selected_node` is the backend counterpart of the frontend's
`useRecordSelection`. Failing to record does not fail the switch: the core
is already on the new node by then, and reporting the switch as failed
would be wrong. It is logged instead.

* fix(core): restoring selections must not prune what the core has not loaded

Putting the profile's selections back when a core starts reused the
reconciliation written for profile switches, and that one also *repairs*:
a record whose group is absent from two snapshots a second apart is
dropped, and the reduced list is written to profiles.yaml.

After a profile switch the configuration is loaded, so absence is
evidence. After a core start it is not — a provider-backed group can be
empty or missing for seconds — and a record pruned on that evidence is
gone for good, because the provider finishing later cannot bring it back.
Restoring now keeps the records and only applies what it can match;
pruning stays with the caller entitled to conclude it.

The restore is also asynchronous: it reads the profile, polls the core
until its groups are readable, then puts its selections. A choice the user
makes inside that window is newer than what it captured, so letting it
finish pushed the core back to the older node while the profile already
held the newer one. Recording a selection now supersedes any activation in
flight — from the tray, and from the UI and chain proxy through
`patch_profile`.

* fix(core): activate the selections of the profile that is actually running

The activation worker read the profiles draft. A profile switch stages its
target there before validating it, so a switch that fails — leaving the
previous profile running — could still have handed an activation the
rejected profile's selections, which it would then apply to whichever
same-named groups the running profile has.

Reading the committed state removes the window. The switch that succeeds
commits before it activates, so nothing changes for that caller; what
changes is that a restore running at core start can no longer observe a
switch that never happened.

* fix(core): stop a restoration from undoing a choice made while it runs

Two gaps in making the profile authoritative, both found by adversarial
review of the commits that introduced it.

A restoration reads the profile's selections once, then polls the core
until its groups can be read — seconds, on a cold start. A selection made
inside that window is newer than what the restoration is carrying, and
nothing told the restoration so: it went on to apply the older choice over
the user's. The UI accepted the new node and traffic snapped back to the
old one, with the profile and the running core then disagreeing. Recording
a selection now abandons any restoration still in flight, through the same
generation counter every other superseding caller uses.

The other gap is the home card in global mode, which passed
`skipConfigSave` and so recorded nothing. That was harmless while nothing
re-applied the profile; now it means the next start undoes the choice. It
was the only caller that ever set the flag, so the flag is gone rather than
flipped — a parameter whose one use was a bug is not worth keeping.

* fix(core): wait for the selections that can be put back, keep trying for the rest

Two gaps in restoring the profile's selections when a core starts, both
found by adversarial review.

Restoring re-checked once, a second later, and stopped. That is enough
after a profile switch, which happens with the configuration already
loaded. A core start is the opposite case: a provider-backed group is
present but empty until its provider finishes loading, and a `select` can
fail while the core is still settling. Neither produces an activation, so
the restore reported success having applied nothing and the group stayed
on the first entry of its `proxies:` list — the outcome restoring exists
to prevent. It now keeps looking, on a deadline, at what the core is
actually on rather than at what it managed to send.

Restoring was also spawned, and the caller enables the system proxy the
moment the start returns — so traffic could be pointed at a core still on
the wrong node. The first pass is now awaited, bounded, and the rest keeps
settling in the background: a core that will not answer delays a start
rather than blocking it, because being proxied through the wrong node
beats not being proxied at all.

TUN is deliberately not covered, and cannot be by anything here: it is
configured in the core's own file, so it carries traffic from the moment
the process starts. What puts a TUN user on the right node from the first
packet is the core's own `cache.db`, which is why the service keeps an
owner's runtime generation across restarts.

`supersede_selected_activation` and `cancel_selected_node_activation` were
the same function under two names, added independently for the same
reason, and `patch_profile` called both. One survives, called once, after
the profile is written — the only placement that needs to exist, since an
activation that read the older profile is cancelled by it and one starting
afterwards reads the newer one.

* fix(core): record a selection by naming it, not by resending the list

Recording a node selection sent the whole selection list, built from the
profile the frontend had rendered. Two selections made before that list
refreshed were therefore built from the same stale snapshot, and the later
write dropped the earlier group's choice. Since a core start re-applies
whatever the profile holds, the dropped one came back on the next restart
— the profile and the running core disagreeing, in the direction the user
would least expect.

The tray already avoided this, because it went through
`record_selected_node`, which merges one group into the profile inside
`with_data_modify`. Exposing that as a command and pointing the frontend
at it leaves one way to record a selection instead of two, and removes the
list from the wire: what a caller knows is the group and the node, and
that is now all it says.

`useRecordSelection` no longer reads the profile at all, which also makes
it stable across renders rather than changing identity whenever the
profile does.

* test(core): make every way of declining to stage answer for itself

`CoreRestarted` was added to `StageRejection` upstream and reached
production without a test. It inherited the right verdict — every
`RestartRequired` is matched together — but nothing said so, and nothing
would have noticed if it had inherited the wrong one.

The list of rejections now goes through a wrapper whose `match` is
exhaustive, so the next variant added upstream fails to compile here. That
is the part worth having: it does not prove the list is complete, but it
does mean nobody can add a way to decline without being sent to this test
to say what it should lead to.

* build(deps): pin the service protocol to v2.6.1

The pin tracked `feat/stage-runtime` because the protocol change it
carried had no tag yet. It has one now, and a branch pin makes the build
irreproducible: an upstream force-push silently changes what this
compiles against.

v2.6.1 carries the runtime generation an owner keeps across restarts,
which is what lets the core hold on to the `cache.db` its node selections
and fake-ip leases live in. The protocol itself is untouched — epoch,
revision and both compatibility floors are byte-identical to v2.6.0 — so
this is a fix release in both directions: an older service still works
with this app, and this app still works with an older service, only
without the durable generation.

The lockfile change is the two lines that name it. Reaching for
`cargo update -p` instead re-resolved a subtree and quietly downgraded
`windows-sys`, `windows-core` and `getrandom` along the way.
2026-07-29 07:47:52 +08:00
Tunglies 5590f6ab15 fix: scope windows-sys dependency to Windows 2026-07-29 05:42:40 +08:00
wonfen cefcb150c9 fix: core runstate review/improve (#7617)
* fix(core): reopen PAC when a start attempt never happens

`save_proxy_ports` closes the PAC endpoint before it stages a candidate,
because the endpoint resolves the Mixed Port through the draft layer and
would otherwise answer with a port nothing is listening on.

Most ways out of that function are a rejection, though: the candidate is
refused and the Core keeps serving on its old ports, having never been
stopped. PAC is re-derived only when the Running Mode changes, and that
is exactly what did not happen — so the endpoint stayed shut for the rest
of the session, and every browser on PAC silently went direct.

Give `core_starting` the counterpart it was missing. `core_start_settled`
re-derives PAC from the Running Mode rather than restoring a saved flag,
which makes it correct on all three endings — a start that succeeded, one
that was abandoned, one that failed and left the Core down — and therefore
safe to run from a guard on every path.

* fix(config): refuse overlapping draft transactions instead of losing an edit

A layer holds exactly one draft, so a second writer's `edit_draft`
overwrites the first writer's staged value in place. `DraftTransaction`
nonetheless rolled back by calling `discard` on the shared layer, which
discarded whatever was staged there — including a change another
transaction was about to commit.

The other transaction then found no draft, and `apply` on an absent draft
does nothing at all. It saved the committed value, returned Ok, and its
side effect had already happened: auto-launch registered with the OS while
the config that describes it says otherwise, and no log line either way.

"Roll back only my edit" cannot be implemented over a single slot, so
enforce the exclusivity the type already assumed. Beginning a transaction
claims every layer and refuses rather than interleaving, which is the same
shape as `try_start_config_update` and `begin_operation` elsewhere.

`patch_verge` is the caller that matters: it holds its draft across
`process_terminated_flags`, which restarts the Core and can take seconds.
The TUN reconciliation runs on every Run State transition and can now lose
that race, so it treats a busy layer as "later" rather than as a failure
worth telling the user about.

* fix(core): reconcile TUN availability when the setting itself changes

Moving the TUN availability guard from the frontend into Rust also moved
what triggers it. The old effect depended on `enable_tun_mode`; the new
reconciliation is spawned from `RealEnv::publish`, so it only runs on a
Run State transition. Those two sets are not the same, and the setting
itself falls in the gap.

Switching TUN on from the global hotkey is the case that reaches it. That
path is not gated on availability — unlike the tray item and the settings
switch, both of which read `tun_capable` — and the flags a TUN patch
raises are answered by a Core reload, which changes no Run State at all.
So on a machine with no Service and no elevation the setting stayed on:
tray icon, settings switch and `enable_tun_mode` in verge.yaml all
reported TUN as enabled while nothing carried its traffic, until some
unrelated core lifecycle transition happened to reconcile it.

Reconcile after any patch that touched the setting. The reconciliation
writes configuration itself, so it goes through the plain apply rather
than back through the patch-and-reconcile form; the absence of a cycle is
then a property of the call graph rather than of a runtime early-return.

`toggle_tun_mode` now reads the setting back instead of returning what it
asked for, so the hotkey cannot report TUN as on moments before the notice
saying it was turned off.

* fix(core): an action already under way is not a decision to put to the user

The legacy status could not distinguish a requested privileged operation
from one already running, because readers blocked until the operation
finished and so never observed the request at all. Run State pushes every
transition instead, and `service_needs_attention` treated any pending
action as a question for the user.

So an install started from the settings page or the home card raised the
migration dialog on top of it, and an uninstall raised one offering to
reinstall the Service being removed. Both offer a button that can only
fail, since the privileged-operation slot is already taken.

An operation in flight is a report of progress. The dialog the user is
already driving keeps itself open through its own loading state.

`tun_should_be_disabled` is unaffected: it already refused to act while an
operation was in flight, so the term this adds is redundant there.

* fix(core): let the snapshot decide whether the Run State has settled

`settled` read the operation slot twice: once to decide whether to wait,
then again inside the snapshot it returned. An operation claiming the slot
between those two reads was described rather than waited for.

`prepare_startup` reads this. A start racing an install would see the
requested install, flatten it to `InstallRequired`, and decide `Wait` —
leaving the core stopped where waiting for the install to finish would
have told it whether the Service came back.

Read the slot once, inside the snapshot, so there is no window rather than
a second check closing it. The rewrite that introduced this also fixed a
lost wakeup here, and that fix stands: the waiter is still registered
before the state is read.

* fix(ui): re-read the Run State once its listener is live

Replacing the poll with a push left a gap. `listen` resolves
asynchronously, so between the first `get_runtime_state` and the
subscription being registered there is a window, and a transition landing
in it is not queued anywhere — it is simply missed. The next event is
whenever the backend happens to move again, which during startup can be a
long time; the 30-second safety net was all that stood behind it, where
the old code polled every two seconds precisely through startup.

The Run State is the one thing here that arrives only by event, so it is
the one thing a missed event leaves stale. Re-read it once every listener
is live, which closes the gap without going back to polling for it.

`onSubscribed` fires even when a registration failed, because a resync is
most needed when a subscription is missing, and not at all after teardown.

* docs(config): state what makes the PAC endpoint's draft read safe

`MixedPort::desired` reads the draft layer, so the PAC endpoint can name a
port the Core has not moved to yet. That is only safe because the one path
staging a listener port closes PAC across the change. Nothing said so at
either end, and the two are in different modules.

* fix(core): ask again when staging goes silent rather than assume it failed

The Service commits the generation before it answers, so a reply that never
arrives is not evidence that nothing was written: config.yaml can already hold
the new configuration while this side concludes the staging never happened. The
Core keeps running the previous configuration, so nothing looks wrong -- until
the Core dies and the Service's watchdog restarts it in the same generation from
whatever config.yaml says, quietly making live a configuration the app reported
as failed.

Silence is the one answer that has to be resolved rather than acted on, so ask
once more before falling back. It is cheap exactly where it matters: staging
plans against the manifest it wrote, so a bundle that already landed copies
nothing and answers in milliseconds, and the Service's lifecycle lock makes a
second ask wait for a first one still in flight instead of interleaving with it.
A deadline keeps that wait off the caller, and a second silence goes where the
first one used to.
2026-07-29 03:58:47 +08:00
oomeow b71a1e4ec5 refactor: mihomo ipc (#7601)
* refactor: mihomo ipc request

* refactor: remove redundant write locks and await on mihomo handle

* fix(rule): handle non-string types in ProviderButton labels

* refactor: handle non-string value types in RuleItem component

* refactor(tauri): remove unnecessary await in get_base_config call

* chore: update tauri-plugin-mihomo deps

* refactor: rename ConnectionId to WsConnectionId

* chore: update tauri-plugin-mihomo-api dependency reference

* chore(config): use Proxy::default in profile test initialization
2026-07-28 15:16:01 +00:00
renovate[bot]renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Tunglies
3515c79e2b chore(deps): update rust crate compact_str to 0.10.0 (#7608)
* chore(deps): update rust crate compact_str to 0.10.0

* fix(deps): align compact_str versions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
2026-07-28 10:47:51 +00:00
Tunglies 95bd5ceed9 fix: update js-yaml imports for ESM 2026-07-28 16:21:06 +08:00
renovate[bot]renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Tunglies
dca6fdcae6 chore(deps): update cargo dependencies (#7443)
* chore(deps): update cargo dependencies

* fix(deps): align shared Rust dependency versions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
2026-07-27 19:02:22 +00:00
Tunglies 2f7e5771ac fix(ci): update agentic workflow runtime 2026-07-28 03:12:49 +08:00